home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Languages / Caml Light 0.7 / cl7tutorial.txt < prev    next >
Encoding:
Text File  |  1995-07-06  |  214.9 KB  |  7,853 lines  |  [TEXT/R*ch]

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18.  
  19.  
  20.  
  21.  
  22.                            Functional programming
  23.  
  24.                               using Caml Light
  25.  
  26.  
  27.                                 Michel Mauny
  28.  
  29.                                 January 1995
  30.  
  31.  
  32.  
  33.  
  34.  
  35.  
  36.  
  37.  
  38.  
  39.  
  40. Contents
  41.  
  42.  
  43.  
  44.  
  45. 1  Introduction                                                            4
  46.  
  47. I Functional programming                                                   6
  48.  
  49. 2  Functional languages                                                    7
  50.    2.1  History of functional languages . . . . . . . . . . . . . . . .    8
  51.    2.2  The ML family . . . . . . . . . . . . . . . . . . . . . . . . .    9
  52.    2.3  The Miranda family. . . . . . . . . . . . . . . . . . . . . . .    9
  53.  
  54. 3  Basic concepts                                                         10
  55.    3.1  Toplevel loop . . . . . . . . . . . . . . . . . . . . . . . . .   10
  56.    3.2  Evaluation:  from expressions to values . . . . . . . . . . . .   11
  57.    3.3  Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . .   13
  58.    3.4  Functions . . . . . . . . . . . . . . . . . . . . . . . . . . .   14
  59.    3.5  Definitions . . . . . . . . . . . . . . . . . . . . . . . . . .   15
  60.    3.6  Partial applications. . . . . . . . . . . . . . . . . . . . . .   16
  61.  
  62. 4  Basic types                                                            18
  63.    4.1  Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . .   18
  64.    4.2  Boolean values. . . . . . . . . . . . . . . . . . . . . . . . .   21
  65.    4.3  Strings and characters. . . . . . . . . . . . . . . . . . . . .   24
  66.    4.4  Tuples. . . . . . . . . . . . . . . . . . . . . . . . . . . . .   24
  67.    4.5  Patterns and pattern-matching . . . . . . . . . . . . . . . . .   25
  68.    4.6  Functions . . . . . . . . . . . . . . . . . . . . . . . . . . .   28
  69.  
  70. 5  Lists                                                                  31
  71.    5.1  Building lists. . . . . . . . . . . . . . . . . . . . . . . . .   31
  72.    5.2  Extracting elements from lists:  pattern-matching . . . . . . .   32
  73.    5.3  Functions over lists. . . . . . . . . . . . . . . . . . . . . .   33
  74.  
  75. 6  User-defined types                                                     36
  76.    6.1  Product types . . . . . . . . . . . . . . . . . . . . . . . . .   36
  77.    6.2  Sum types . . . . . . . . . . . . . . . . . . . . . . . . . . .   39
  78.    6.3  Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . .   44
  79.  
  80. II Caml Light specifics                                                   47
  81.  
  82. 7  Mutable data structures                                                48
  83.    7.1  User-defined mutable data structures. . . . . . . . . . . . . .   48
  84.  
  85.  
  86.                                      1
  87.  
  88.  
  89.  
  90.    7.2  The ref type. . . . . . . . . . . . . . . . . . . . . . . . . .   50
  91.    7.3  Arrays. . . . . . . . . . . . . . . . . . . . . . . . . . . . .   50
  92.    7.4  Loops:  while and for . . . . . . . . . . . . . . . . . . . . .   52
  93.    7.5  Polymorphism and mutable data structures. . . . . . . . . . . .   53
  94.  
  95. 8  Escaping from computations:  exceptions                                55
  96.    8.1  Exceptions. . . . . . . . . . . . . . . . . . . . . . . . . . .   55
  97.    8.2  Raising an exception. . . . . . . . . . . . . . . . . . . . . .   56
  98.    8.3  Trapping exceptions . . . . . . . . . . . . . . . . . . . . . .   57
  99.    8.4  Polymorphism and exceptions . . . . . . . . . . . . . . . . . .   58
  100.  
  101. 9  Basic input/output                                                     60
  102.    9.1  Printable types . . . . . . . . . . . . . . . . . . . . . . . .   60
  103.    9.2  Output. . . . . . . . . . . . . . . . . . . . . . . . . . . . .   62
  104.    9.3  Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . .   63
  105.    9.4  Channels on files . . . . . . . . . . . . . . . . . . . . . . .   63
  106.  
  107. 10 Streams and parsers                                                    66
  108.    10.1 Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . .   66
  109.    10.2 Stream matching and parsers . . . . . . . . . . . . . . . . . .   68
  110.    10.3 Parameterized parsers . . . . . . . . . . . . . . . . . . . . .   70
  111.    10.4 Further reading . . . . . . . . . . . . . . . . . . . . . . . .   78
  112.  
  113. 11 Standalone programs and separate compilation                           79
  114.    11.1 Standalone programs . . . . . . . . . . . . . . . . . . . . . .   79
  115.    11.2 Programs in several files . . . . . . . . . . . . . . . . . . .   80
  116.    11.3 Abstraction . . . . . . . . . . . . . . . . . . . . . . . . . .   82
  117.  
  118. III A complete example                                                    84
  119.  
  120. 12 ASL: A Small Language                                                  85
  121.    12.1 ASL abstract syntax trees . . . . . . . . . . . . . . . . . . .   85
  122.    12.2 Parsing ASL programs. . . . . . . . . . . . . . . . . . . . . .   86
  123.  
  124. 13 Untyped semantics of ASL programs                                      92
  125.    13.1 Semantic values . . . . . . . . . . . . . . . . . . . . . . . .   92
  126.    13.2 Semantic functions. . . . . . . . . . . . . . . . . . . . . . .   93
  127.    13.3 Examples. . . . . . . . . . . . . . . . . . . . . . . . . . . .   94
  128.  
  129. 14 Encoding recursion                                                     95
  130.    14.1 Fixpoint combinators. . . . . . . . . . . . . . . . . . . . . .   95
  131.    14.2 Recursion as a primitive construct. . . . . . . . . . . . . . .   97
  132.  
  133. 15 Static typing, polymorphism and type synthesis                         98
  134.    15.1 The type system . . . . . . . . . . . . . . . . . . . . . . . .   98
  135.    15.2 The algorithm . . . . . . . . . . . . . . . . . . . . . . . . .  103
  136.    15.3 The ASL type-synthesizer. . . . . . . . . . . . . . . . . . . .  105
  137.  
  138. 16 Compiling ASL to an abstract machine code                             114
  139.    16.1 The Abstract Machine. . . . . . . . . . . . . . . . . . . . . .  114
  140.    16.2 Compiling ASL programs into CAM code. . . . . . . . . . . . . .  117
  141.  
  142.  
  143.                                      2
  144.  
  145.  
  146.  
  147.    16.3 Execution of CAM code . . . . . . . . . . . . . . . . . . . . .  119
  148.  
  149. 17 Answers to exercises                                                  122
  150.  
  151. 18 Conclusions and further reading                                       134
  152.  
  153.  
  154.  
  155.  
  156.  
  157.  
  158.  
  159.  
  160.  
  161.  
  162.  
  163.  
  164.  
  165.  
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172.  
  173.  
  174.  
  175.  
  176.  
  177.  
  178.  
  179.  
  180.  
  181.  
  182.  
  183.  
  184.  
  185.  
  186.  
  187.  
  188.  
  189.  
  190.  
  191.  
  192.  
  193.  
  194.  
  195.  
  196.  
  197.  
  198.  
  199.  
  200.                                      3
  201.  
  202.  
  203.  
  204.  
  205.  
  206.  
  207.  
  208.  
  209.  
  210. Chapter 1
  211.  
  212.  
  213.  
  214. Introduction
  215.  
  216.  
  217.  
  218. This document is a tutorial introduction to functional programming, and,
  219. more precisely, to the usage of Caml Light.  It has been used to teach Caml
  220. Light(1) in different universities and is intended for beginners.  It
  221. contains numerous examples and exercises, and absolute beginners should read
  222. it while sitting in front of a Caml Light toplevel loop, testing examples
  223. and variations by themselves.
  224.   After generalities about functional programming, some features specific to
  225. Caml Light are described.  ML type synthesis and a simple execution model
  226. are presented in a complete example of prototyping a subset of ML.
  227.   Part I (chapters 2--6) may be skipped by users familiar with ML. Users
  228. with experience in functional programming, but unfamiliar with the ML
  229. dialects may skip the very first chapters and start at chapter 6, learning
  230. the Caml Light syntax from the examples.  Part I starts with some intuition
  231. about functions and types and gives an overview of ML and other functional
  232. languages (chapter 2).  Chapter 3 outlines the interaction with the Caml
  233. Light toplevel loop and its basic objects.  Basic types and some of their
  234. associated primitives are presented in chapter 4.  Lists (chapter 5) and
  235. user-defined types (chapter 6) are structured data allowing for the
  236. representation of complex objects and their easy creation and
  237. destructuration.
  238.   While concepts presented in part I are common (under one form or another)
  239. to many functional languages, part B (chapters 7--11) is dedicated to
  240. features specific to Caml Light:  mutable data structures (chapter 7),
  241. exception handling (chapter 8), input/output (chapter 9) and streams and
  242. parsers (chapter 10) show a more imperative side of the language.
  243. Standalone programs and separate compilation (chapter 11) allow for modular
  244. programming and the creation of standalone applications.  Concise examples
  245. of Caml Light features are to be found in this part.
  246.   Part C (chapters 12--16) is meant for already experienced Caml Light users
  247. willing to know more about how the Caml Light compiler synthesizes the types
  248. of expression and how compilation and evaluation proceeds.  Some knowledge
  249. about first-order unification is assumed.  The presentation is rather
  250.  
  251. ------------------------------
  252.  1. The ``Caml  Strong'' version  of these notes  is available  as an  INRIA
  253. technical report [24].
  254.  
  255.  
  256.                                      4
  257.  
  258.  
  259.  
  260. informal, and is sometimes terse (specially in the chapter about type
  261. synthesis).  We prototype a small and simple functional language (called
  262. ASL): we give the complete prototype implementation, from the ASL parser to
  263. the symbolic execution of code.  Lexing and parsing of ASL programs are
  264. presented in chapter 12, providing realistic usages of streams and parsers.
  265. Chapter 13 presents an untyped call-by-value semantics of ASL programs
  266. through the definition of an ASL interpreter.  The encoding of recursion in
  267. untyped ASL is presented in chapter 14, showing the expressive power of the
  268. language.  The type synthesis of functional programs is demonstrated in
  269. chapter 15, using destructive unification (on first-order terms representing
  270. types) as a central tool.  Chapter 16 introduces the Categorical Abstract
  271. Machine:  a simple execution model for call-by-value functional programs.
  272. Although the Caml Light execution model is different from the one presented
  273. here, an intuition about the simple compilation of functional languages can
  274. be found in this chapter.
  275.  
  276.   Warning:  The programs and remarks (especially contained in parts B and C)
  277. might not be valid in Caml Light versions different from 0.7.
  278.  
  279.  
  280.  
  281.  
  282.  
  283.  
  284.  
  285.  
  286.  
  287.  
  288.  
  289.  
  290.  
  291.  
  292.  
  293.  
  294.  
  295.  
  296.  
  297.  
  298.  
  299.  
  300.  
  301.  
  302.  
  303.  
  304.  
  305.  
  306.  
  307.  
  308.  
  309.  
  310.  
  311.  
  312.  
  313.                                      5
  314.  
  315.  
  316.  
  317.  
  318.  
  319.  
  320.  
  321.  
  322.  
  323.  
  324.  
  325.  
  326.  
  327.  
  328.  
  329.  
  330.  
  331.  
  332.  
  333.  
  334.                                    Part I
  335.  
  336.  
  337.  
  338.                            Functional programming
  339.  
  340.  
  341.  
  342.  
  343.  
  344.  
  345.  
  346.  
  347.  
  348.  
  349.  
  350.  
  351.  
  352.  
  353.  
  354.  
  355.  
  356.  
  357.  
  358.  
  359.  
  360.  
  361.  
  362.  
  363.  
  364.  
  365.  
  366.  
  367.  
  368.  
  369.  
  370.                                      6
  371.  
  372.  
  373.  
  374.  
  375.  
  376.  
  377.  
  378.  
  379.  
  380. Chapter 2
  381.  
  382.  
  383.  
  384. Functional languages
  385.  
  386.  
  387.  
  388. Programming languages are said to be functional when the basic way of
  389. structuring programs is the notion of function and their essential control
  390. structure is function application.  For example, the Lisp language [22], and
  391. more precisely its modern successor Scheme [31, 1], has been called
  392. functional because it possesses these two properties.
  393.   However, we want the programming notion of function to be as close as
  394. possible to the usual mathematical notion of function.  In mathematics,
  395. functions are ``first-class'' objects:  they can be arbitrarily manipulated.
  396. For example, they can be composed, and the composition function is itself a
  397. function.
  398.   In mathematics, one would present the successor function in the following
  399. way:
  400.  
  401.                            successor:  N -> N
  402.                                        n |-> n+1
  403.  
  404. The functional composition could be presented as:
  405.  
  406.                        o:  (A=>B)x (C=>A) -> (C=>B)
  407.                            (f,g) |-> (x |-> f (g x))
  408.  
  409. where (A=>B) denotes the space of functions from A to B.
  410.   We remark here the importance of:
  411.  
  412. 1.  the notion of type; a mathematical function always possesses a domain
  413.     and a codomain.  They will correspond to the programming notion of type.
  414.  
  415. 2.  lexical binding:  when we wrote the mathematical definition of
  416.     successor, we have assumed that the addition function + had been
  417.     previously defined, mapping a pair of natural numbers to a natural
  418.     number; the meaning of the successor function is defined using the
  419.     meaning of the addition:  whatever + denotes in the future, this
  420.     successor function will remain the same.
  421.  
  422. 3.  the notion of functional abstraction, allowing to express the behavior
  423.     of fog as (x |-> f (g x)), i.e.  the function which, when given some x,
  424.  
  425.  
  426.                                      7
  427.  
  428.  
  429.  
  430.     returns f (g x).
  431.  
  432. ML dialects (cf.  below) respect these notions.  But they also allow
  433. non-functional programming styles, and, in this sense, they are functional
  434. but not purely functional.
  435.  
  436.  
  437. 2.1 History of functional languages
  438.  
  439. Some historical points:
  440.  
  441.  -  1930:  Alonzo Church developed the l-calculus [6] as an attempt to
  442.     provide a basis for mathematics.  The l-calculus is a formal theory for
  443.     functionality.  The three basic constructs of the l-calculus are:
  444.  
  445.  
  446.      -  variable names (e.g.  x, y,...);
  447.  
  448.      -  application (MN if M and M are terms);
  449.  
  450.      -  functional abstraction (lx.M).
  451.  
  452.  
  453.     Terms of the l-calculus represent functions.  The pure l-calculus has
  454.     been proved inconsistent as a logical theory.  Some type systems have
  455.     been added to it in order to remedy this inconsistency.
  456.  
  457.  -  1958:  Mac Carthy invented Lisp [22] whose programs have some
  458.     similarities with terms of the l-calculus.  Lisp dialects have been
  459.     recently evolving in order to be closer to modern functional languages
  460.     (Scheme), but they still do not possess a type system.
  461.  
  462.  -  1965:  P. Landin proposed the ISWIM [18] language (for ``If You See What
  463.     I Mean''), which is the precursor of languages of the ML family.
  464.  
  465.  -  1978:  J. Backus introduced FP: a language of combinators [3] and a
  466.     framework in which it is possible to reason about programs.  The main
  467.     particularity of FP programs is that they have no variable names.
  468.  
  469.  -  1978:  R. Milner proposes a language called ML [11], intended to be the
  470.     metalanguage of the LCF proof assistant (i.e.  the language used to
  471.     program the search of proofs).  This language is inspired by ISWIM
  472.     (close to l-calculus) and possesses an original type system.
  473.  
  474.  -  1985:  D. Turner proposed the Miranda [36] programming language, which
  475.     uses Milner's type system but where programs are submitted to lazy
  476.     evaluation.
  477.  
  478. Currently, the two main families of functional languages are the ML and the
  479. Miranda families.
  480.  
  481.  
  482.  
  483.                                      8
  484.  
  485.  
  486.  
  487. 2.2 The ML family
  488.  
  489. ML languages are based on a sugared(1) version of l-calculus.  Their
  490. evaluation regime is call-by-value (i.e.  the argument is evaluated before
  491. being passed to a function), and they use Milner's type system.
  492.   The LCF proof system appeared in 1972 at Stanford (Stanford LCF). It has
  493. been further developed at Cambridge (Cambridge LCF) where the ML language
  494. was added to it.
  495.   From 1981 to 1986, a version of ML and its compiler was developed in a
  496. collaboration between INRIA and Cambridge by G. Cousineau, G. Huet and L.
  497. Paulson.
  498.   In 1981, L. Cardelli implemented a version of ML whose compiler generated
  499. native machine code.
  500.   In 1984, a committee of researchers from the universities of Edinburgh and
  501. Cambridge, Bell Laboratories and INRIA, headed by R. Milner worked on a new
  502. extended language called Standard ML [28].  This core language was completed
  503. by a module facility designed by D. MacQueen [23].
  504.   Since 1984, the Caml language has been under design in a collaboration
  505. between INRIA and LIENS(2)). Its first release appeared in 1987.  The main
  506. implementors of Caml were Ascander Suarez, Pierre Weis and Michel Mauny.
  507.   In 1989 appeared Standard ML of New-Jersey, developed by Andrew Appel
  508. (Princeton University) and David MacQueen (Bell Laboratories).
  509.   Caml Light is a smaller, more portable implementation of the core Caml
  510. language, developed by Xavier Leroy since 1990.
  511.  
  512.  
  513. 2.3 The Miranda family
  514.  
  515. All languages in this family use lazy evaluation (i.e.  the argument of a
  516. function is evaluated if and when the function needs its value---arguments
  517. are passed unevaluated to functions).  They also use Milner's type system.
  518.   Languages belonging to the Miranda family find their origin in the SASL
  519. language [34] (1976) developed by D. Turner.  SASL and its successors (KRC
  520. [35] 1981, Miranda [36] 1985 and Haskell [15] 1990) use sets of mutually
  521. recursive equations as programs.  These equations are written in a script
  522. (collection of declarations) and the user may evaluate expressions using
  523. values defined in this script.  LML (Lazy ML) has been developed in Goteborg
  524. (Sweeden); its syntax is close to ML's syntax and it uses a fast execution
  525. model:  the G-machine [16].
  526.  
  527.  
  528.  
  529.  
  530.  
  531.  
  532.  
  533.  
  534.  
  535. ------------------------------
  536.  1. i.e.  with a more user-friendly syntax.
  537.  2. Laboratoire d'Informatique de l'Ecole Normale Superieure, 45 Rue  d'Ulm,
  538. 75005 Paris
  539.  
  540.  
  541.                                      9
  542.  
  543.  
  544.  
  545.  
  546.  
  547.  
  548.  
  549.  
  550.  
  551. Chapter 3
  552.  
  553.  
  554.  
  555. Basic concepts
  556.  
  557.  
  558.  
  559. We examine in this chapter some fundamental concepts which we will use and
  560. study in the following chapters.  Some of them are specific to the interface
  561. with the Caml language (toplevel, global definitions) while others are
  562. applicable to any functional language.
  563.  
  564.  
  565. 3.1 Toplevel loop
  566.  
  567. The first contact with Caml is through its interactive aspect(1).  When
  568. running Caml on a computer, we enter a toplevel loop where Caml waits for
  569. input from the user, and then gives a response to what has been entered.
  570.   The beginning of a Caml Light session looks like this (assuming $ is the
  571. shell prompt on the host machine):
  572.  
  573. $camllight
  574. >       Caml Light version 0.6
  575.  
  576. #
  577.  
  578. On the PC version, the command is called caml.
  579.   The ``#'' character is Caml's prompt.  When this character appears at the
  580. beginning of a line in an actual Caml Light session, the toplevel loop is
  581. waiting for a new toplevel phrase to be entered.
  582.   Throughout this document, the phrases starting by the # character
  583. represent legal input to Caml.  Since this document has been pre-processed
  584. by Caml Light and these lines have been effectively given as input to a Caml
  585. Light process, the reader may reproduce by him/herself the session contained
  586. in each chapter (each chapter of the first two parts contains a different
  587. session, the third part is a single session).  Lines starting with the ``>''
  588. character are Caml Light error messages.  Lines starting by another
  589. character are either Caml responses or (possibly) illegal input.  The input
  590.  
  591. ------------------------------
  592.  1. Caml  Light implementations  also  possess a  batch compiler  usable  to
  593. compile files and produce standalone applications; this will be discussed in
  594. chapter 11.
  595.  
  596.  
  597.  
  598.                                      10
  599.  
  600.  
  601.  
  602. is printed in typewriter font (like this), and output is written using
  603. slanted typewriter font (like that).
  604.   Important:  Of course, when developing non-trivial programs, it is
  605. preferable to edit programs in files and then to include the files in the
  606. toplevel, instead of entering the programs directly.  Furthermore, when
  607. debugging, it is very useful to trace some functions, to see with what
  608. arguments they are called, and what result they return.  See the reference
  609. manual [20] for a description of these facilities.
  610.  
  611.  
  612. 3.2 Evaluation:  from expressions to values
  613.  
  614. Let us enter an arithmetic expression and see what is Caml's response:
  615.  
  616. #1+2;;
  617. - : int = 3
  618.  
  619. The expression ``1+2'' has been entered, followed by ``;;'' which represents
  620. the end of the current toplevel phrase.  When encountering ``;;'', Caml
  621. enters the type-checking (more precisely type synthesis) phase, and prints
  622. the inferred type for the expression.  Then, it compiles code for the
  623. expression, executes it and, finally, prints the result.
  624.   In the previous example, the result of evaluation is printed as ``3'' and
  625. the type is ``int'':  the type of integers.
  626.   The process of evaluation of a Caml expression can be seen as transforming
  627. this expression until no further transformation is allowed.  These
  628. transformations must preserve semantics.  For example, if the expression
  629. ``1+2'' has the mathematical object 3 as semantics, then the result ``3''
  630. must have the same semantics.  The different phases of the Caml evaluation
  631. process are:
  632.  
  633.  -  parsing (checking the syntactic legality of input);
  634.  
  635.  -  type synthesis;
  636.  
  637.  -  compiling;
  638.  
  639.  -  loading;
  640.  
  641.  -  executing;
  642.  
  643.  -  printing the result of execution.
  644.  
  645. Let us consider another example:  the application of the successor function
  646. to 2+3.  The expression (function x -> x+1) should be read as ``the function
  647. that, given x, returns x+1''.  The juxtaposition of this expression to (2+3)
  648. is function application.
  649.  
  650. #(function x -> x+1) (2+3);;
  651. - : int = 6
  652.  
  653.  
  654.  
  655.                                      11
  656.  
  657.  
  658.  
  659. There are several ways to reduce that value before obtaining the result 6.
  660. Here are two of them (the expression being reduced at each step is
  661. underlined):
  662.  
  663.             (function x -> x+1) (2+3)  (function x -> x+1) (2+3)
  664.                                 ------ --------------------------
  665.                         |                          |
  666.               (function x -> x+1) 5            (2+3) + 1
  667.               ----------------------           ------
  668.                         |                          |
  669.                        5+1                        5+1
  670.                        ----                       ----
  671.                         |                          |
  672.                         6                          6
  673.  
  674.   The transformations used by Caml during evaluation cannot be described in
  675. this chapter, since they imply knowledge about compilation of Caml programs
  676. and machine representation of Caml values.  However, since the basic control
  677. structure of Caml is function application, it is quite easy to give an idea
  678. of the transformations involved in the Caml evaluation process by using the
  679. kind of rewriting we used in the last example.  The evaluation of the
  680. (well-typed) application e1(e2), where e1 and e2 denote arbitrary
  681. expressions, consists in the following steps:
  682.  
  683.  -  Evaluate e2, obtaining its value v.
  684.  
  685.  -  Evaluate e1 until it becomes a functional value.  Because of the
  686.     well-typing hypothesis, e1 must represent a function from some type t1
  687.     to some t2, and the type of v is t1.  We will write (function x -> e)
  688.     for the result of the evaluation of e1.  It denotes the mathematical
  689.     object usually written as:
  690.  
  691.  
  692.                 f:  t1->t2
  693.                     x|->e (where, of course, e may depend on x)
  694.  
  695.  
  696.     N.B.:  We do not evaluate e before we know the value of x.
  697.  
  698.  -  Evaluate e where v has been substituted for all occurrences of x.  We
  699.     then get the final value of the original expression.  The result is of
  700.     type t2.
  701.  
  702. In the previous example, we evaluate:
  703.  
  704.  -  2+3 to 5;
  705.  
  706.  -  (function x -> x+1) to itself (it is already a function body);
  707.  
  708.  -  x+1 where 5 is substituted for x, i.e.  evaluate 5+1, getting 6 as
  709.     result.
  710.  
  711. It should be noticed that Caml uses call-by-value:  arguments are evaluated
  712. before being passed to functions.  The relative evaluation order of the
  713.  
  714.  
  715.                                      12
  716.  
  717.  
  718.  
  719. functional expression and of the argument expression is
  720. implementation-dependent, and should not be relied upon.  The Caml Light
  721. implementation evaluates arguments before functions (right-to-left
  722. evaluation), as shown above; the original Caml implementation evaluates
  723. functions before arguments (left-to-right evaluation).
  724.  
  725.  
  726. 3.3 Types
  727.  
  728. Types and their checking/synthesis are crucial to functional programming:
  729. they provide an indication about the correctness of programs.
  730.   The universe of Caml values is partitioned into types.  A type represents
  731. a collection of values.  For example, int is the type of integer numbers,
  732. and float is the type of floating-point numbers.  Truth values belong to the
  733. bool type.  Character strings belong to the string type.  Types are divided
  734. into two classes:
  735.  
  736.  -  Basic types (int, bool, string, ...).
  737.  
  738.  -  Compound types such as functional types.  For example, the type of
  739.     functions from integers to integers is denoted by int -> int.  The type
  740.     of functions from boolean values to character strings is written
  741.     bool -> string.  The type of pairs whose first component is an integer
  742.     and whose second component is a boolean value is written int * bool.
  743.  
  744. In fact, any combination of the types above (and even more!)  is possible.
  745. This could be written as:
  746.  
  747.      BasicType ::=  int
  748.                   | bool
  749.                   | string
  750.  
  751.      Type      ::=  BasicType
  752.                   | Type -> Type
  753.                   | Type * Type
  754.  
  755. Once a Caml toplevel phrase has been entered in the computer, the Caml
  756. process starts analyzing it.  First of all, it performs syntax analysis,
  757. which consists in checking whether the phrase belongs to the language or
  758. not.  For example, here is a syntax error(2) (a parenthesis is missing):
  759.  
  760. #(function x -> x+1 (2+3);;
  761. Toplevel input:
  762. >(function x -> x+1 (2+3);;
  763. >                        ^^
  764. Syntax error.
  765.  
  766. ------------------------------
  767.  2. Actually,  lexical  analysis  takes  place before  syntax  analysis  and
  768. lexical errors  may occur,  detecting for  instance badly  formed  character
  769. constants.
  770.  
  771.  
  772.  
  773.                                      13
  774.  
  775.  
  776.  
  777. The carets ``^^^'' underline the location where the error was detected.
  778.   The second analysis performed is type analysis:  the system attempts to
  779. assign a type to each subexpression of the phrase, and to synthesize the
  780. type of the whole phrase.  If type analysis fails (i.e.  if the system is
  781. unable to assign a sensible type to the phrase), then a type error is
  782. reported and Caml waits for another input, rejecting the current phrase.
  783. Here is a type error (cannot add a number to a boolean):
  784.  
  785. #(function x -> x+1) (2+true);;
  786. Toplevel input:
  787. >(function x -> x+1) (2+true);;
  788. >                       ^^^^
  789. This expression has type bool,
  790. but is used with type int.
  791.  
  792. The rejection of ill-typed phrases is called strong typing.  Compilers for
  793. weakly typed languages (C, for example) would instead issue a warning
  794. message and continue their work at the risk of getting a ``Bus error'' or
  795. ``Illegal instruction'' message at run-time.
  796.   Once a sensible type has been deduced for the expression, then the
  797. evaluation process (compilation, loading and execution) may begin.
  798.   Strong typing enforces writing clear and well-structured programs.
  799. Moreover, it adds security and increases the speed of program development,
  800. since most typos and many conceptual errors are trapped and signaled by the
  801. type analysis.  Finally, well-typed programs do not need dynamic type tests
  802. (the addition function does not need to test whether or not its arguments
  803. are numbers), hence static type analysis allows for more efficient machine
  804. code.
  805.  
  806.  
  807. 3.4 Functions
  808.  
  809. The most important kind of values in functional programming are functional
  810. values.  Mathematically, a function f of type A->B is a rule of
  811. correspondence which associates with each element of type A a unique member
  812. of type B.
  813.   If x denotes an element of A, then we will write f(x) for the application
  814. of f to x.  Parentheses are often useless (they are used only for grouping
  815. subexpressions), so we could also write (f(x)) as well as (f((x))) or simply
  816. f x.  The value of f x is the unique element of B associated with x by the
  817. rule of correspondence for f.
  818.   The notation f(x) is the one normally employed in mathematics to denote
  819. functional application.  However, we shall be careful not to confuse a
  820. function with its application.  We say ``the function f with formal
  821. parameter x'', meaning that f has been defined by:
  822.  
  823.                                   f:x|->e
  824.  
  825. or, in Caml, that the body of f is something like (function x -> ...).
  826. Functions are values as other values.  In particular, functions may be
  827. passed as arguments to other functions, and/or returned as result.  For
  828.  
  829.  
  830.                                      14
  831.  
  832.  
  833.  
  834. example, we could write:
  835.  
  836. #function f -> (function x -> (f(x+1) - 1));;
  837. - : (int -> int) -> int -> int = <fun>
  838.  
  839. That function takes as parameter a function (let us call it f) and returns
  840. another function which, when given an argument (let us call it x), will
  841. return the predecessor of the value of the application f(x+1).
  842.   The type of that function should be read as:
  843. (int -> int) -> (int -> int).
  844.  
  845.  
  846. 3.5 Definitions
  847.  
  848. It is important to give names to values.  We have already seen some named
  849. values:  we called them formal parameters.  In the expression
  850. (function x -> x+1), the name x is a formal parameter.  Its name is
  851. irrelevant:  changing it into another one does not change the meaning of the
  852. expression.  We could have written that function (function y -> y+1).
  853.   If now we apply this function to, say, 1+2, we will evaluate the
  854. expression y+1 where y is the value of 1+2.  Naming y the value of 1+2 in
  855. y+1 is written as:
  856.  
  857. #let y=1+2 in y+1;;
  858. - : int = 4
  859.  
  860. This expression is a legal Caml phrase, and the let construct is indeed
  861. widely used in Caml programs.
  862.   The let construct introduces local bindings of values to identifiers.
  863. They are local because the scope of y is restricted to the expression (y+1).
  864. The identifier y kept its previous binding (if any) after the evaluation of
  865. the ``let ...in . ..'' construct.  We can check that y has not been
  866. globally defined by trying to evaluate it:
  867.  
  868. #y;;
  869. Toplevel input:
  870. >y;;
  871. >^
  872. The value identifier y is unbound.
  873.  
  874. Local bindings using let also introduce sharing of (possibly time-consuming)
  875. evaluations.  When evaluating ``let x=e1 in e2'', e1 gets evaluated only
  876. once.  All occurrences of x in e2 access the value of e1 which has been
  877. computed once.  For example, the computation of:
  878.  
  879. let big = sum_of_prime_factors 35461243
  880. in big+(2+big)-(4*(big+1));;
  881.  
  882. will be less expensive than:
  883.  
  884.   (sum_of_prime_factors 35461243)
  885.  
  886.  
  887.                                      15
  888.  
  889.  
  890.  
  891. + (2 + (sum_of_prime_factors 35461243))
  892. - (4 * (sum_of_prime_factors 35461243 + 1));;
  893.  
  894. The let construct also has a global form for toplevel declarations, as in:
  895.  
  896. #let successor = function x -> x+1;;
  897. successor : int -> int = <fun>
  898.  
  899. #let square = function x -> x*x;;
  900. square : int -> int = <fun>
  901.  
  902. When a value has been declared at toplevel, it is of course available during
  903. the rest of the session.
  904.  
  905. #square(successor 3);;
  906. - : int = 16
  907.  
  908. #square;;
  909. - : int -> int = <fun>
  910.  
  911.   When declaring a functional value, there are some alternative syntaxes
  912. available.  For example we could have declared the square function by:
  913.  
  914. #let square x = x*x;;
  915. square : int -> int = <fun>
  916.  
  917. or (closer to the mathematical notation) by:
  918.  
  919. #let square (x) = x*x;;
  920. square : int -> int = <fun>
  921.  
  922. All these definitions are equivalent.
  923.  
  924.  
  925. 3.6 Partial applications
  926.  
  927. A partial application is the application of a function to some but not all
  928. of its arguments.  Consider, for example, the function f defined by:
  929.  
  930. #let f x = function y -> 2*x+y;;
  931. f : int -> int -> int = <fun>
  932.  
  933. Now, the expression f(3) denotes the function which when given an argument y
  934. returns the value of 2*3+y.  The application f(x) is called a partial
  935. application, since f waits for two successive arguments, and is applied to
  936. only one.  The value of f(x) is still a function.
  937.   We may thus define an addition function by:
  938.  
  939. #let addition x = function y -> x+y;;
  940. addition : int -> int -> int = <fun>
  941.  
  942.  
  943.  
  944.                                      16
  945.  
  946.  
  947.  
  948. This can also be written:
  949.  
  950. #let addition x y = x+y;;
  951. addition : int -> int -> int = <fun>
  952.  
  953. We can then define the successor function by:
  954.  
  955. #let successor = addition 1;;
  956. successor : int -> int = <fun>
  957.  
  958. Now, we may use our successor function:
  959.  
  960. #successor (successor 1);;
  961. - : int = 3
  962.  
  963.  
  964.  
  965. Exercises
  966.  
  967. Exercise 3.1 Give examples of functions with the following types:
  968.  
  969. 1.  (int -> int) -> int
  970.  
  971. 2.  int -> (int -> int)
  972.  
  973. 3.  (int -> int) -> (int -> int)
  974.  
  975. Exercise 3.2 We have seen that the names of formal parameters are
  976. meaningless.  It is then possible to rename x by y in (function x -> x+x).
  977. What should we do in order to rename x in y in
  978.  
  979. (function x -> (function y -> x+y))
  980.  
  981. Hint:  rename y by z first.  Question:  why?
  982.  
  983. Exercise 3.3 Evaluate the following expressions (rewrite them until no
  984. longer possible):
  985.  
  986. let x=1+2 in ((function y -> y+x) x);;
  987. let x=1+2 in ((function x -> x+x) x);;
  988. let f1 = function f2 -> (function x -> f2 x)
  989. in let g = function x -> x+1
  990.    in f1 g 2;;
  991.  
  992.  
  993.  
  994.  
  995.  
  996.  
  997.  
  998.  
  999.  
  1000.  
  1001.                                      17
  1002.  
  1003.  
  1004.  
  1005.  
  1006.  
  1007.  
  1008.  
  1009.  
  1010.  
  1011. Chapter 4
  1012.  
  1013.  
  1014.  
  1015. Basic types
  1016.  
  1017.  
  1018.  
  1019. We examine in this chapter the Caml basic types.
  1020.  
  1021.  
  1022. 4.1 Numbers
  1023.  
  1024. Caml Light provides two numeric types:  integers (type int) and
  1025. floating-point numbers (type float).  Integers are limited to the range
  1026. -230... 230-1.  Integer arithmetic is taken modulo 231 ; that is, an
  1027. integer operation that overflows does not raise an error, but the result
  1028. simply wraps around.  Predefined operations (functions) on integers include:
  1029.  
  1030.                         +  addition
  1031.                         -  subtraction and unary minus
  1032.                         *  multiplication
  1033.                         /  division
  1034.                       mod  modulo
  1035.  
  1036.   Some examples of expressions:
  1037.  
  1038. #3 * 4 + 2;;
  1039. - : int = 14
  1040.  
  1041. #3 * (4 + 2);;
  1042. - : int = 18
  1043.  
  1044. #3 - 7 - 2;;
  1045. - : int = -6
  1046.  
  1047. There are precedence rules that make * bind tighter than +, and so on.  In
  1048. doubt, write extra parentheses.
  1049.   So far, we have not seen the type of these arithmetic operations.  They
  1050. all expect two integer arguments; so, they are functions taking one integer
  1051. and returning a function from integers to integers.  The (functional) value
  1052. of such infix identifiers may be obtained by taking their prefix version.
  1053.  
  1054. #prefix + ;;
  1055.  
  1056.  
  1057.                                      18
  1058.  
  1059.  
  1060.  
  1061. - : int -> int -> int = <fun>
  1062.  
  1063. #prefix * ;;
  1064. - : int -> int -> int = <fun>
  1065.  
  1066. #prefix mod ;;
  1067. - : int -> int -> int = <fun>
  1068.  
  1069.   As shown by their types, the infix operators +, *, ..., do not work on
  1070. floating-point values.  A separate set of floating-point arithmetic
  1071. operations is provided:
  1072.  
  1073.                           +.  addition
  1074.                           -.  subtraction and unary minus
  1075.                           *.  multiplication
  1076.                           /.  division
  1077.                         sqrt  square root
  1078.                     exp, log  exponentiation and logarithm
  1079.                sin, cos,.. .  usual trigonometric operations
  1080.  
  1081.   We have two conversion functions to go back and forth between integers and
  1082. floating-point numbers:  int_of_float and float_of_int.
  1083.  
  1084. #1 + 2.3;;
  1085. Toplevel input:
  1086. >1 + 2.3;;
  1087. >    ^^^
  1088. This expression has type float,
  1089. but is used with type int.
  1090.  
  1091. #float_of_int 1 +. 2.3;;
  1092. - : float = 3.3
  1093.  
  1094.   Let us now give some examples of numerical functions.  We start by
  1095. defining some very simple functions on numbers:
  1096.  
  1097. #let square x = x *. x;;
  1098. square : float -> float = <fun>
  1099.  
  1100. #square 2.0;;
  1101. - : float = 4.0
  1102.  
  1103. #square (2.0 /. 3.0);;
  1104. - : float = 0.444444444444
  1105.  
  1106. #let sum_of_squares (x,y) = square(x) +. square(y);;
  1107. sum_of_squares : float * float -> float = <fun>
  1108.  
  1109. #let half_pi = 3.14159 /. 2.0
  1110. #in sum_of_squares(cos(half_pi), sin(half_pi));;
  1111. - : float = 1.0
  1112.  
  1113.  
  1114.                                      19
  1115.  
  1116.  
  1117.  
  1118.   We now develop a classical example:  the computation of the root of a
  1119. function by Newton's method.  Newton's method can be stated as follows:  if
  1120. y is an approximation to a root of a function f, then:
  1121.  
  1122.                                      f(y)
  1123.                                  y -------
  1124.                                     f'(y)
  1125.  
  1126. is a better approximation, where f'(y) is the derivative of f evaluated at
  1127. y.  For example, with f(x)=x2 -a, we have f'(x) =2x, and therefore:
  1128.  
  1129.                                                 a
  1130.                             f(y)      y2- a  y +--
  1131.                                                 y
  1132.                          y- ------=y- ------=-----
  1133.                             f'(y)      2y      2
  1134.  
  1135.   We can define a function deriv for approximating the derivative of a
  1136. function at a given point by:
  1137.  
  1138. #let deriv f x dx = (f(x+.dx) -. f(x)) /. dx;;
  1139. deriv : (float -> float) -> float -> float -> float = <fun>
  1140.  
  1141. Provided dx is sufficiently small, this gives a reasonable estimate of the
  1142. derivative of f at x.
  1143.   The following function returns the absolute value of its floating point
  1144. number argument.  It uses the ``if ...then . ..else'' conditional
  1145. construct.
  1146.  
  1147. #let abs x = if x >. 0.0 then x else -. x;;
  1148. abs : float -> float = <fun>
  1149.  
  1150. The main function, given below, uses three local functions.  The first one,
  1151. until, is an example of a recursive function:  it calls itself in its body,
  1152. and is defined using a let rec construct (rec shows that the definition is
  1153. recursive).  It takes three arguments:  a predicate p on floats, a function
  1154. change from floats to floats, and a float x.  If p(x) is false, then until
  1155. is called with last argument change(x), otherwise, x is the result of the
  1156. whole call.  We will study recursive functions more closely later.  The two
  1157. other auxiliary functions, satisfied and improve, take a float as argument
  1158. and deliver respectively a boolean value and a float.  The function
  1159. satisfied asks wether the image of its argument by f is smaller than epsilon
  1160. or not, thus testing wether y is close enough to a root of f.  The function
  1161. improve computes the next approximation using the formula given below.  The
  1162. three local functions are defined using a cascade of let constructs.  The
  1163. whole function is:
  1164.  
  1165. #let newton f epsilon =
  1166. #  let rec until p change x =
  1167. #            if p(x) then x
  1168. #            else until p change (change(x)) in
  1169. #  let satisfied y = abs(f y) <. epsilon in
  1170. #  let improve y = y -. (f(y) /. (deriv f y epsilon))
  1171. #in until satisfied improve;;
  1172.  
  1173.  
  1174.                                      20
  1175.  
  1176.  
  1177.  
  1178. newton : (float -> float) -> float -> float -> float = <fun>
  1179.  
  1180. Some examples of equation solving:
  1181.  
  1182. #let square_root x epsilon =
  1183. #           newton (function y -> y*.y -. x) epsilon x
  1184. #and cubic_root x epsilon =
  1185. #           newton (function y -> y*.y*.y -. x) epsilon x;;
  1186. square_root : float -> float -> float = <fun>
  1187. cubic_root : float -> float -> float = <fun>
  1188.  
  1189. #square_root 2.0 1e-5;;
  1190. - : float = 1.41421569553
  1191.  
  1192. #cubic_root 8.0 1e-5;;
  1193. - : float = 2.00000000131
  1194.  
  1195. #2.0 *. (newton cos 1e-5 1.5);;
  1196. - : float = 3.14159265359
  1197.  
  1198.  
  1199.  
  1200. 4.2 Boolean values
  1201.  
  1202. The presence of the conditional construct implies the presence of boolean
  1203. values.  The type bool is composed of two values true and false.
  1204.  
  1205. #true;;
  1206. - : bool = true
  1207.  
  1208. #false;;
  1209. - : bool = false
  1210.  
  1211. The functions with results of type bool are often called predicates.  Many
  1212. predicates are predefined in Caml.  Here are some of them:
  1213.  
  1214. #prefix <;;
  1215. - : 'a -> 'a -> bool = <fun>
  1216.  
  1217. #1 < 2;;
  1218. - : bool = true
  1219.  
  1220. #prefix <.;;
  1221. - : float -> float -> bool = <fun>
  1222.  
  1223. #3.14159 <. 2.718;;
  1224. - : bool = false
  1225.  
  1226. There exist also <=, >, >=, and similarly <=., >., >=..
  1227.  
  1228.  
  1229.  
  1230.  
  1231.                                      21
  1232.  
  1233.  
  1234.  
  1235. 4.2.1 Equality
  1236.  
  1237. Equality has a special status in functional languages because of functional
  1238. values.  It is easy to test equality of values of base types (integers,
  1239. floating-point numbers, booleans, ...):
  1240.  
  1241. #1 = 2;;
  1242. - : bool = false
  1243.  
  1244. #false = (1>2);;
  1245. - : bool = true
  1246.  
  1247. But it is impossible, in the general case, to decide the equality of
  1248. functional values.  Hence, equality stops on a run-time error when it
  1249. encounters functional values.
  1250.  
  1251. #(fun x -> x) = (fun x -> x);;
  1252. Uncaught exception: Invalid_argument "equal: functional value"
  1253.  
  1254. Since equality may be used on values of any type, what is its type?
  1255. Equality takes two arguments of the same type (whatever type it is) and
  1256. returns a boolean value.  The type of equality is a polymorphic type, i.e.
  1257. may take several possible forms.  Indeed, when testing equality of two
  1258. numbers, then its type is int -> int -> bool, and when testing equality of
  1259. strings, its type is string -> string -> bool.
  1260.  
  1261. #prefix =;;
  1262. - : 'a -> 'a -> bool = <fun>
  1263.  
  1264. The type of equality uses type variables, written 'a, `b, etc.  Any type can
  1265. be substituted to type variables in order to produces specific instances of
  1266. types.  For example, substituting int for 'a above produces
  1267. int -> int -> bool, which is the type of the equality function used on
  1268. integer values.
  1269.  
  1270. #1=2;;
  1271. - : bool = false
  1272.  
  1273. #(1,2) = (2,1);;
  1274. - : bool = false
  1275.  
  1276. #1 = (1,2);;
  1277. Toplevel input:
  1278. >1 = (1,2);;
  1279. >     ^^^
  1280. This expression has type int * int,
  1281. but is used with type int.
  1282.  
  1283.  
  1284.  
  1285.  
  1286.  
  1287.  
  1288.                                      22
  1289.  
  1290.  
  1291.  
  1292. 4.2.2 Conditional
  1293.  
  1294. Conditional expressions are of the form ``if etest then e1 else e2'', where
  1295. etest is an expression of type bool and e1, e2 are expressions possessing
  1296. the same type.  As an example, the logical negation could be written:
  1297.  
  1298. #let negate a = if a then false else true;;
  1299. negate : bool -> bool = <fun>
  1300.  
  1301. #negate (1=2);;
  1302. - : bool = true
  1303.  
  1304.  
  1305. 4.2.3 Logical operators
  1306.  
  1307. The classical logical operators are available in Caml.  Disjunction and
  1308. conjunction are respectively written or and &:
  1309.  
  1310. #true or false;;
  1311. - : bool = true
  1312.  
  1313. #(1<2) & (2>1);;
  1314. - : bool = true
  1315.  
  1316. The operators & and or are not functions.  They should not be seen as
  1317. regular functions, since they evaluate their second argument only if it is
  1318. needed.  For example, the or operator evaluates its second operand only if
  1319. the first one evaluates to false.  The behavior of these operators may be
  1320. described as follows:
  1321.  
  1322.            e1  or e2  is equivalent to if e1  then true else e2
  1323.            e1  & e2   is equivalent to if e1  then e2 else false
  1324.  
  1325. Negation is predefined:
  1326.  
  1327. #not true;;
  1328. - : bool = false
  1329.  
  1330. The not identifier receives a special treatment from the parser:  the
  1331. application ``not f x'' is recognized as ``not (f x)'' while ``f g x'' is
  1332. identical to ``(f g) x''.  This special treatment explains why the
  1333. functional value associated to not can be obtained only using the prefix
  1334. keyword:
  1335.  
  1336. #prefix not;;
  1337. - : bool -> bool = <fun>
  1338.  
  1339.  
  1340.  
  1341.  
  1342.  
  1343.  
  1344.  
  1345.                                      23
  1346.  
  1347.  
  1348.  
  1349. 4.3 Strings and characters
  1350.  
  1351. String constants (type string) are written between " characters
  1352. (double-quotes).  Single-character constants (type char) are written between
  1353. ` characters (backquotes).  The most used string operation is string
  1354. concatenation, denoted by the ^ character.
  1355.  
  1356. #"Hello" ^ " World!";;
  1357. - : string = "Hello World!"
  1358.  
  1359. #prefix ^;;
  1360. - : string -> string -> string = <fun>
  1361.  
  1362. Characters are ASCII characters:
  1363.  
  1364. #`a`;;
  1365. - : char = `a`
  1366.  
  1367. #`\065`;;
  1368. - : char = `A`
  1369.  
  1370. and can be built from their ASCII code as in:
  1371.  
  1372. #char_of_int 65;;
  1373. - : char = `A`
  1374.  
  1375. Other operations are available (sub_string, int_of_char, etc).  See the Caml
  1376. Light reference manual [20] for complete information.
  1377.  
  1378.  
  1379. 4.4 Tuples
  1380.  
  1381. 4.4.1 Constructing tuples
  1382.  
  1383. It is possible to combine values into tuples (pairs, triples, ...).  The
  1384. value constructor for tuples is the ``,'' character (the comma).  We will
  1385. often use parentheses around tuples in order to improve readability, but
  1386. they are not strictly necessary.
  1387.  
  1388. #1,2;;
  1389. - : int * int = 1, 2
  1390.  
  1391. #1,2,3,4;;
  1392. - : int * int * int * int = 1, 2, 3, 4
  1393.  
  1394. #let p = (1+2, 1<2);;
  1395. p : int * bool = 3, true
  1396.  
  1397. The infix ``*'' identifier is the type constructor for tuples.  For
  1398. instance, t1t2 corresponds to the mathematical cartesian product of types
  1399. t1 and t2.
  1400.  
  1401.  
  1402.                                      24
  1403.  
  1404.  
  1405.  
  1406.   We can build tuples from any values:  the tuple value constructor is
  1407. generic.
  1408.  
  1409. 4.4.2 Extracting pair components
  1410.  
  1411. Projection functions are used to extract components of tuples.  For pairs,
  1412. we have:
  1413.  
  1414. #fst;;
  1415. - : 'a * 'b -> 'a = <fun>
  1416.  
  1417. #snd;;
  1418. - : 'a * 'b -> 'b = <fun>
  1419.  
  1420. They have polymorphic types, of course, since they may be applied to any
  1421. kind of pair.  They are predefined in the Caml system, but could be defined
  1422. by the user (in fact, the cartesian product itself could be defined --- see
  1423. section 6.1, dedicated to user-defined product types):
  1424.  
  1425. #let first (x,y) = x
  1426. #and second (x,y) = y;;
  1427. first : 'a * 'b -> 'a = <fun>
  1428. second : 'a * 'b -> 'b = <fun>
  1429.  
  1430. #first p;;
  1431. - : int = 3
  1432.  
  1433. #second p;;
  1434. - : bool = true
  1435.  
  1436. We say that first is a generic value because it works uniformly on several
  1437. kinds of arguments (provided they are pairs).  We often confuse between
  1438. ``generic'' and ``polymorphic'', saying that such value is polymorphic
  1439. instead of generic.
  1440.  
  1441.  
  1442. 4.5 Patterns and pattern-matching
  1443.  
  1444. Patterns and pattern-matching play an important role in ML languages.  They
  1445. appear in all real programs and are strongly related to types (predefined or
  1446. user-defined).
  1447.   A pattern indicates the shape of a value.  Patterns are ``values with
  1448. holes''.  A single variable (formal parameter) is a pattern (with no shape
  1449. specified:  it matches any value).  When a value is matched against a
  1450. pattern (this is called pattern-matching), the pattern acts as a filter.  We
  1451. already used patterns and pattern-matching in all the functions we wrote:
  1452. the function body (function x -> ...)  does (trivial) pattern-matching.
  1453. When applied to a value, the formal parameter x gets bound to that value.
  1454. The function body (function (x,y) -> x+y) does also pattern-matching:  when
  1455. applied to a value (a pair, because of well-typing hypotheses), the x and y
  1456. get bound respectively to the first and the second component of that pair.
  1457.  
  1458.  
  1459.                                      25
  1460.  
  1461.  
  1462.  
  1463.   All these pattern-matching examples were trivial ones, they did not
  1464. involve any test:
  1465.  
  1466.  -  formal parameters such as x do not impose any particular shape to the
  1467.     value they are supposed to match;
  1468.  
  1469.  -  pair patterns such as (x,y) always match for typing reasons (cartesian
  1470.     product is a product type).
  1471.  
  1472. However, some types do not guarantee such a uniform shape to their values.
  1473. Consider the bool type:  an element of type bool is either true or false.
  1474. If we impose to a value of type bool to have the shape of true, then
  1475. pattern-matching may fail.  Consider the following function:
  1476.  
  1477. #let f = function true -> false;;
  1478. Toplevel input:
  1479. >let f = function true -> false;;
  1480. >        ^^^^^^^^^^^^^^^^^^^^^^
  1481. Warning: this matching is not exhaustive.
  1482. f : bool -> bool = <fun>
  1483.  
  1484. The compiler warns us that the pattern-matching may fail (we did not
  1485. consider the false case).
  1486.   Thus, if we apply f to a value that evaluates to true, pattern-matching
  1487. will succeed (an equality test is performed during execution).
  1488.  
  1489. #f (1<2);;
  1490. - : bool = false
  1491.  
  1492. But, if f's argument evaluates to false, a run-time error is reported:
  1493.  
  1494. #f (1>2);;
  1495. Uncaught exception: Match_failure ("", 1346, 1368)
  1496.  
  1497. Here is a correct definition using pattern-matching:
  1498.  
  1499. #let negate = function true -> false
  1500. #                    | false -> true;;
  1501. negate : bool -> bool = <fun>
  1502.  
  1503. The pattern-matching has now two cases, separated by the ``|'' character.
  1504. Cases are examined in turn, from top to bottom.  An equivalent definition of
  1505. negate would be:
  1506.  
  1507. #let negate = function true -> false
  1508. #                    | x -> true;;
  1509. negate : bool -> bool = <fun>
  1510.  
  1511. The second case now matches any boolean value (in fact, only false since
  1512. true has been caught by the first match case).  When the second case is
  1513. chosen, the identifier x gets bound to the argument of negate, and could be
  1514.  
  1515.  
  1516.                                      26
  1517.  
  1518.  
  1519.  
  1520. used in the right-hand part of the match case.  Since in our example we do
  1521. not use the value of the argument in the right-hand part of the second match
  1522. case, another equivalent definition of negate would be:
  1523.  
  1524. #let negate = function true -> false
  1525. #                    | _ -> true;;
  1526. negate : bool -> bool = <fun>
  1527.  
  1528. Where ``_'' acts as a formal paramenter (matches any value), but does not
  1529. introduce any binding:  it should be read as ``anything else''.
  1530.   As an example of pattern-matching, consider the following function
  1531. definition (truth value table of implication):
  1532.  
  1533. #let imply = function (true,true) -> true
  1534. #                   | (true,false) -> false
  1535. #                   | (false,true) -> true
  1536. #                   | (false,false) -> true;;
  1537. imply : bool * bool -> bool = <fun>
  1538.  
  1539. Here is another way of defining imply, by using variables:
  1540.  
  1541. #let imply = function (true,x) -> x
  1542. #                   | (false,x) -> true;;
  1543. imply : bool * bool -> bool = <fun>
  1544.  
  1545. Simpler, and simpler again:
  1546.  
  1547. #let imply = function (true,x) -> x
  1548. #                   | (false,_) -> true;;
  1549. imply : bool * bool -> bool = <fun>
  1550.  
  1551. #let imply = function (true,false) -> false
  1552. #                   | _ -> true;;
  1553. imply : bool * bool -> bool = <fun>
  1554.  
  1555. Pattern-matching is allowed on any type of value (non-trivial
  1556. pattern-matching is only possible on types with data constructors).
  1557.   For example:
  1558.  
  1559. #let is_zero = function 0 -> true | _ -> false;;
  1560. is_zero : int -> bool = <fun>
  1561.  
  1562. #let is_yes = function "oui" -> true
  1563. #                    | "si" -> true
  1564. #                    | "ya" -> true
  1565. #                    | "yes" -> true
  1566. #                    | _ -> false;;
  1567. is_yes : string -> bool = <fun>
  1568.  
  1569.  
  1570.  
  1571.  
  1572.  
  1573.                                      27
  1574.  
  1575.  
  1576.  
  1577. 4.6 Functions
  1578.  
  1579. The type constructor ``->'' is predefined and cannot be defined in ML's type
  1580. system.  We shall explore in this section some further aspects of functions
  1581. and functional types.
  1582.  
  1583. 4.6.1 Functional composition
  1584.  
  1585. Functional composition is easily definable in Caml.  It is of course a
  1586. polymorphic function:
  1587.  
  1588. #let compose f g = function x -> f (g (x));;
  1589. compose : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b = <fun>
  1590.  
  1591. The type of compose contains no more constraints than the ones appearing in
  1592. the definition:  in a sense, it is the most general type compatible with
  1593. these constraints.
  1594.   These constraints are:
  1595.  
  1596.  -  the codomain of g and the domain of f must be the same;
  1597.  
  1598.  -  x must belong to the domain of g;
  1599.  
  1600.  -  compose f g x will belong to the codomain of f.
  1601.  
  1602.   Let's see compose at work:
  1603.  
  1604. #let succ x = x+1;;
  1605. succ : int -> int = <fun>
  1606.  
  1607. #compose succ list_length;;
  1608. - : '_a list -> int = <fun>
  1609.  
  1610. #(compose succ list_length) [1;2;3];;
  1611. - : int = 4
  1612.  
  1613.  
  1614. 4.6.2 Currying
  1615.  
  1616. We can define two versions of the addition function:
  1617.  
  1618. #let plus = function (x,y) -> x+y;;
  1619. plus : int * int -> int = <fun>
  1620.  
  1621. #let add = function x -> (function y -> x+y);;
  1622. add : int -> int -> int = <fun>
  1623.  
  1624. These two functions differ only in their way of taking their arguments.  The
  1625. first one will take an argument belonging to a cartesian product, the second
  1626. one will take a number and return a function.  The add function is said to
  1627. be the curried version of plus (in honor of the logician Haskell Curry).
  1628.  
  1629.  
  1630.                                      28
  1631.  
  1632.  
  1633.  
  1634.   The currying transformation may be written in Caml under the form of a
  1635. higher-order function:
  1636.  
  1637. #let curry f = function x -> (function y -> f(x,y));;
  1638. curry : ('a * 'b -> 'c) -> 'a -> 'b -> 'c = <fun>
  1639.  
  1640. Its inverse function may be defined by:
  1641.  
  1642. #let uncurry f = function (x,y) -> f x y;;
  1643. uncurry : ('a -> 'b -> 'c) -> 'a * 'b -> 'c = <fun>
  1644.  
  1645. We may check the types of curry and uncurry on particular examples:
  1646.  
  1647. #uncurry (prefix +);;
  1648. - : int * int -> int = <fun>
  1649.  
  1650. #uncurry (prefix ^);;
  1651. - : string * string -> string = <fun>
  1652.  
  1653. #curry plus;;
  1654. - : int -> int -> int = <fun>
  1655.  
  1656.  
  1657.  
  1658. Exercises
  1659.  
  1660. Exercise 4.1 Define functions that compute the surface area and the volume
  1661. of well-known geometric objects (rectangles, circles, spheres, ...).
  1662.  
  1663. Exercise 4.2 What would happen in a language submitted to call-by-value
  1664. with recursion if there was no conditional construct (if ...  then ...  else
  1665. ...)?
  1666.  
  1667. Exercise 4.3 Define the factorial function such that:
  1668.  
  1669.                       factorial n= n*(n -1)* ... *2* 1
  1670.  
  1671. Give two versions of factorial:  recursive and tail recursive.
  1672.  
  1673. Exercise 4.4 Define the fibonacci function that, when given a number n,
  1674. returns the nth Fibonacci number, i.e.  the nth term un of the sequence
  1675. defined by:
  1676.  
  1677.                                u1= 1
  1678.                                u2= 1
  1679.                                un+2= un+1+un
  1680.  
  1681. Exercise 4.5 What are the types of the following expressions?
  1682.  
  1683.  -  uncurry compose
  1684.  
  1685.  
  1686.  
  1687.                                      29
  1688.  
  1689.  
  1690.  
  1691.  -  compose curry uncurry
  1692.  
  1693.  -  compose uncurry curry
  1694.  
  1695.  
  1696.  
  1697.  
  1698.  
  1699.  
  1700.  
  1701.  
  1702.  
  1703.  
  1704.  
  1705.  
  1706.  
  1707.  
  1708.  
  1709.  
  1710.  
  1711.  
  1712.  
  1713.  
  1714.  
  1715.  
  1716.  
  1717.  
  1718.  
  1719.  
  1720.  
  1721.  
  1722.  
  1723.  
  1724.  
  1725.  
  1726.  
  1727.  
  1728.  
  1729.  
  1730.  
  1731.  
  1732.  
  1733.  
  1734.  
  1735.  
  1736.  
  1737.  
  1738.  
  1739.  
  1740.  
  1741.  
  1742.  
  1743.  
  1744.                                      30
  1745.  
  1746.  
  1747.  
  1748.  
  1749.  
  1750.  
  1751.  
  1752.  
  1753.  
  1754. Chapter 5
  1755.  
  1756.  
  1757.  
  1758. Lists
  1759.  
  1760.  
  1761.  
  1762. Lists represent an important data structure, mainly because of their success
  1763. in the Lisp language.  Lists in ML are homogeneous:  a list cannot contain
  1764. elements of different types.  This may be annoying to new ML users, yet
  1765. lists are not as fundamental as in Lisp, since ML provides a facility for
  1766. introducing new types allowing the user to define more precisely the data
  1767. structures needed by the program (cf.  chapter 6).
  1768.  
  1769.  
  1770. 5.1 Building lists
  1771.  
  1772. Lists are empty or non empty sequences of elements.  They are built with two
  1773. value constructors:
  1774.  
  1775.  -  [], the empty list (read:  nil);
  1776.  
  1777.  -  ::, the non-empty list constructor (read:  cons).  It takes an element e
  1778.     and a list l, and builds a new list whose first element (head) is e and
  1779.     rest (tail) is l.
  1780.  
  1781. The special syntax [e1; ...; en ] builds the list whose elements are
  1782. e1,... ,en.  It is equivalent to e1 :: (e2 :: .. .(en :: []). ..).
  1783.   We may build lists of numbers:
  1784.  
  1785. #1::2::[];;
  1786. - : int list = [1; 2]
  1787.  
  1788. #[3;4;5];;
  1789. - : int list = [3; 4; 5]
  1790.  
  1791. #let x=2 in [1; 2; x+1; x+2];;
  1792. - : int list = [1; 2; 3; 4]
  1793.  
  1794. Lists of functions:
  1795.  
  1796. #let adds =
  1797. #  let add x y = x+y
  1798. #  in [add 1; add 2; add 3];;
  1799.  
  1800.  
  1801.                                      31
  1802.  
  1803.  
  1804.  
  1805. adds : (int -> int) list = [<fun>; <fun>; <fun>]
  1806.  
  1807. and indeed, lists of anything desired.
  1808.   We may wonder what are the types of the list (data) constructors.  The
  1809. empty list is a list of anything (since it has no element), it has thus the
  1810. type ``list of anything''.  The list constructor :: takes an element and a
  1811. list (containing elements with the same type) and returns a new list.  Here
  1812. again, there is no type constraint on the elements considered.
  1813.  
  1814. #[];;
  1815. - : 'a list = []
  1816.  
  1817. #function head -> function tail -> head::tail;;
  1818. - : 'a -> 'a list -> 'a list = <fun>
  1819.  
  1820. We see here that the list type is a recursive type.  The :: constructor
  1821. receives two arguments; the second argument is itself a list.
  1822.  
  1823.  
  1824. 5.2 Extracting elements from lists:  pattern-matching
  1825.  
  1826. We know how to build lists; we now show how to test emptiness of lists
  1827. (although the equality predicate could be used for that) and extract
  1828. elements from lists (e.g.  the first one).  We have used pattern-matching on
  1829. pairs, numbers or boolean values.  The syntax of patterns also includes list
  1830. patterns.  (We will see that any data constructor can actually be used in a
  1831. pattern.)  For lists, at least two cases have to be considered (empty, non
  1832. empty):
  1833.  
  1834. #let is_null = function [] -> true | _ -> false;;
  1835. is_null : 'a list -> bool = <fun>
  1836.  
  1837. #let head = function x::_ -> x
  1838. #                  | _ -> raise (Failure "head");;
  1839. head : 'a list -> 'a = <fun>
  1840.  
  1841. #let tail = function _::l -> l
  1842. #                  | _ -> raise (Failure "tail");;
  1843. tail : 'a list -> 'a list = <fun>
  1844.  
  1845. The expression raise (Failure "head") will produce a run-time error when
  1846. evaluated.  In the definition of head above, we have chosen to forbid taking
  1847. the head of an empty list.  We could have chosen tail [] to evaluate to [],
  1848. but we cannot return a value for head [] without changing the type of the
  1849. head function.
  1850.   We say that the types list and bool are sum types, because they are
  1851. defined with several alternatives:
  1852.  
  1853.  -  a list is either [] or :: of ...
  1854.  
  1855.  -  a boolean value is either true or false
  1856.  
  1857.  
  1858.                                      32
  1859.  
  1860.  
  1861.  
  1862.   Lists and booleans are typical examples of sum types.  Sum types are the
  1863. only types whose values need run-time tests in order to be matched by a
  1864. non-variable pattern (i.e.  a pattern that is not a single variable).
  1865.   The cartesian product is a product type (only one alternative).  Product
  1866. types do not involve run-time tests during pattern-matching, because the
  1867. type of their values suffices to indicate statically what their structure
  1868. is.
  1869.  
  1870.  
  1871. 5.3 Functions over lists
  1872.  
  1873. We will see in this section the definition of some useful functions over
  1874. lists.  These functions are of general interest, but are not exhaustive.
  1875. Some of them are predefined in the Caml Light system.  See also [9] or [37]
  1876. for other examples of functions over lists.
  1877.   Computation of the length of a list:
  1878.  
  1879. #let rec length = function [] -> 0
  1880. #                        | _::l -> 1 + length(l);;
  1881. length : 'a list -> int = <fun>
  1882.  
  1883. #length [true; false];;
  1884. - : int = 2
  1885.  
  1886. Concatenating two lists:
  1887.  
  1888. #let rec append =
  1889. #     function [], l2 -> l2
  1890. #            | (x::l1), l2 -> x::(append (l1,l2));;
  1891. append : 'a list * 'a list -> 'a list = <fun>
  1892.  
  1893. The append function is already defined in Caml, and bound to the infix
  1894. identifier @.
  1895.  
  1896. #[1;2] @ [3;4];;
  1897. - : int list = [1; 2; 3; 4]
  1898.  
  1899. Reversing a list:
  1900.  
  1901. #let rec rev = function [] -> []
  1902. #                     | x::l -> (rev l) @ [x];;
  1903. rev : 'a list -> 'a list = <fun>
  1904.  
  1905. #rev [1;2;3];;
  1906. - : int list = [3; 2; 1]
  1907.  
  1908.   The map function applies a function on all the elements of a list, and
  1909. return the list of the function results.  It demonstrates full functionality
  1910. (it takes a function as argument), list processing, and polymorphism (note
  1911. the sharing of type variables between the arguments of map in its type).
  1912.  
  1913.  
  1914.  
  1915.                                      33
  1916.  
  1917.  
  1918.  
  1919. #let rec map f =
  1920. #    function [] -> []
  1921. #           | x::l -> (f x)::(map f l);;
  1922. map : ('a -> 'b) -> 'a list -> 'b list = <fun>
  1923.  
  1924. #map (function x -> x+1) [1;2;3;4;5];;
  1925. - : int list = [2; 3; 4; 5; 6]
  1926.  
  1927. #map length [ [1;2;3]; [4;5]; [6]; [] ];;
  1928. - : int list = [3; 2; 1; 0]
  1929.  
  1930.   The following function is a list iterator.  It takes a function f, a base
  1931. element a and a list [x1;...;xn].  It computes:
  1932.  
  1933.           itlist f a [x1;. ..; xn]=f (. ..(f (f a x1) x2)  ...)xn
  1934.  
  1935. For instance, when applied to the curried addition function, to the base
  1936. element 0, and to a list of numbers, it computes the sum of all elements in
  1937. the list.  The expression:
  1938.  
  1939.     it_list (prefix +) 0 [1;2;3;4;5]
  1940.  
  1941.     evaluates to ((((0+1)+2)+3)+4)+5
  1942.  
  1943.     i.e.  to 15.
  1944.  
  1945. #let rec it_list f a =
  1946. #        function [] -> a
  1947. #               | x::l -> it_list f (f a x) l;;
  1948. it_list : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a = <fun>
  1949.  
  1950. #let sigma = it_list prefix + 0;;
  1951. sigma : int list -> int = <fun>
  1952.  
  1953. #sigma [1;2;3;4;5];;
  1954. - : int = 15
  1955.  
  1956. #it_list (prefix *) 1 [1;2;3;4;5];;
  1957. - : int = 120
  1958.  
  1959. The it_list function is one of the many ways to iterate over a list.  For
  1960. other list iteration functions, see [9].
  1961.  
  1962.  
  1963. Exercises
  1964.  
  1965. Exercise 5.1 Define the combine function which, when given a pair of lists,
  1966. returns a list of pairs such that:
  1967.  
  1968. combine ([x1;...;xn],[y1;...;yn]) = [(x1,y1);...;(xn,yn)]
  1969.  
  1970.  
  1971.  
  1972.                                      34
  1973.  
  1974.  
  1975.  
  1976. The function generates a run-time error if the argument lists do not have
  1977. the same length.
  1978.  
  1979. Exercise 5.2 Define a function which, when given a list, returns the list
  1980. of all its sublists.
  1981.  
  1982.  
  1983.  
  1984.  
  1985.  
  1986.  
  1987.  
  1988.  
  1989.  
  1990.  
  1991.  
  1992.  
  1993.  
  1994.  
  1995.  
  1996.  
  1997.  
  1998.  
  1999.  
  2000.  
  2001.  
  2002.  
  2003.  
  2004.  
  2005.  
  2006.  
  2007.  
  2008.  
  2009.  
  2010.  
  2011.  
  2012.  
  2013.  
  2014.  
  2015.  
  2016.  
  2017.  
  2018.  
  2019.  
  2020.  
  2021.  
  2022.  
  2023.  
  2024.  
  2025.  
  2026.  
  2027.  
  2028.  
  2029.                                      35
  2030.  
  2031.  
  2032.  
  2033.  
  2034.  
  2035.  
  2036.  
  2037.  
  2038.  
  2039. Chapter 6
  2040.  
  2041.  
  2042.  
  2043. User-defined types
  2044.  
  2045.  
  2046.  
  2047. The user is allowed to define his/her own data types.  With this facility,
  2048. there is no need to encode the data structures that must be manipulated by a
  2049. program into lists (as in Lisp) or into arrays (as in Fortran).
  2050. Furthermore, early detection of type errors is enforced, since user-defined
  2051. data types reflect precisely the needs of the algorithms.
  2052.   Types are either:
  2053.  
  2054.  -  product types,
  2055.  
  2056.  -  or sum types.
  2057.  
  2058.   We have already seen examples of both kinds of types:  the bool and list
  2059. types are sum types (they contain values with different shapes and are
  2060. defined and matched using several alternatives).  The cartesian product is
  2061. an example of a product type:  we know statically the shape of values
  2062. belonging to cartesian products.
  2063.   In this chapter, we will see how to define and use new types in Caml.
  2064.  
  2065.  
  2066. 6.1 Product types
  2067.  
  2068. Product types are finite labeled products of types.  They are a
  2069. generalization of cartesian product.  Elements of product types are called
  2070. records.
  2071.  
  2072. 6.1.1 Defining product types
  2073.  
  2074. An example:  suppose we want to define a data structure containing
  2075. information about individuals.  We could define:
  2076.  
  2077. #let jean=("Jean",23,"Student","Paris");;
  2078. jean : string * int * string * string = "Jean", 23, "Student", "Paris"
  2079.  
  2080. and use pattern-matching to extract any particular information about the
  2081. person jean.  The problem with such usage of cartesian product is that a
  2082. function name_of returning the name field of a value representing an
  2083.  
  2084.  
  2085.                                      36
  2086.  
  2087.  
  2088.  
  2089. individual would have the same type as the general first projection for
  2090. 4-tuples (and indeed would be the same function).  This type is not precise
  2091. enough since it allows for the application of the function to any 4-uple,
  2092. and not only to values such as jean.
  2093.   Instead of using cartesian product, we define a person data type:
  2094.  
  2095. #type person =
  2096. #  {Name:string; Age:int; Job:string; City:string};;
  2097. Type person defined.
  2098.  
  2099. The type person is the product of string, int, string and string.  The field
  2100. names provide type information and also documentation:  it is much easier to
  2101. understand data structures such as jean above than arbitrary tuples.
  2102.   We have labels (i.e.  Name, ...) to refer to components of the products.
  2103. The order of appearance of the products components is not relevant:  labels
  2104. are sufficient to uniquely identify the components.  The Caml system finds a
  2105. canonical order on labels to represent and print record values.  The order
  2106. is always the order which appeared in the definition of the type.
  2107.   We may now define the individual jean as:
  2108.  
  2109. #let jean = {Job="Student"; City="Paris";
  2110. #            Name="Jean"; Age=23};;
  2111. jean : person = {Name="Jean"; Age=23; Job="Student"; City="Paris"}
  2112.  
  2113. This example illustrates the fact that order of labels is not relevant.
  2114.  
  2115. 6.1.2 Extracting products components
  2116.  
  2117. The canonical way of extracting product components is pattern-matching.
  2118. Pattern-matching provides a way to mention the shape of values and to give
  2119. (local) names to components of values.  In the following example, we name n
  2120. the numerical value contained in the field Age of the argument, and we
  2121. choose to forget values contained in other fields (using the _ character).
  2122.  
  2123. #let age_of = function
  2124. #     {Age=n; Name=_; Job=_; City=_} -> n;;
  2125. age_of : person -> int = <fun>
  2126.  
  2127. #age_of jean;;
  2128. - : int = 23
  2129.  
  2130. It is also possible to access the value of a single field, with the .  (dot)
  2131. operator:
  2132.  
  2133. #jean.Age;;
  2134. - : int = 23
  2135.  
  2136. #jean.Job;;
  2137. - : string = "Student"
  2138.  
  2139. Labels always refer to the most recent type definition:  when two record
  2140.  
  2141.  
  2142.                                      37
  2143.  
  2144.  
  2145.  
  2146. types possess some common labels, then these labels always refer to the most
  2147. recently defined type.  When using modules (see section 11.2) this problem
  2148. arises for types defined in the same module.  For types defined in different
  2149. modules, the full name of labels (i.e.  with the name of the modules
  2150. prepended) disambiguates such situations.
  2151.  
  2152. 6.1.3 Parameterized product types
  2153.  
  2154. It is important to be able to define parameterized types in order to define
  2155. generic data structures.  The list type is parameterized, and this is the
  2156. reason why we may build lists of any kind of values.  If we want to define
  2157. the cartesian product as a Caml type, we need type parameters because we
  2158. want to be able to build cartesian product of any pair of types.
  2159.  
  2160. #type ('a,'b) pair = {Fst:'a; Snd:'b};;
  2161. Type pair defined.
  2162.  
  2163. #let first x = x.Fst and second x = x.Snd;;
  2164. first : ('a, 'b) pair -> 'a = <fun>
  2165. second : ('a, 'b) pair -> 'b = <fun>
  2166.  
  2167. #let p={Snd=true; Fst=1+2};;
  2168. p : (int, bool) pair = {Fst=3; Snd=true}
  2169.  
  2170. #first(p);;
  2171. - : int = 3
  2172.  
  2173. Warning:  the pair type is similar to the Caml cartesian product *, but it
  2174. is a different type.
  2175.  
  2176. #fst p;;
  2177. Toplevel input:
  2178. >fst p;;
  2179. >    ^
  2180. This expression has type (int, bool) pair,
  2181. but is used with type 'a * 'b.
  2182.  
  2183. Actually, any two type definitions produce different types.  If we enter
  2184. again the previous definition:
  2185.  
  2186. #type ('a,'b) pair = {Fst:'a; Snd:'b};;
  2187. Type pair defined.
  2188.  
  2189. we cannot any longer extract the Fst component of x:
  2190.  
  2191. #p.Fst;;
  2192. Toplevel input:
  2193. >p.Fst;;
  2194. >^
  2195. This expression has type (int, bool) pair,
  2196. but is used with type ('a, 'b) pair.
  2197.  
  2198.  
  2199.                                      38
  2200.  
  2201.  
  2202.  
  2203. since the label Fst refers to the latter type pair that we defined, while
  2204. p's type is the former pair.
  2205.  
  2206.  
  2207. 6.2 Sum types
  2208.  
  2209. A sum type is the finite labeled disjoint union of several types.  A sum
  2210. type definition defines a type as being the union of some other types.
  2211.  
  2212. 6.2.1 Defining sum types
  2213.  
  2214. Example:  we want to have a type called identification whose values can be:
  2215.  
  2216.  -  either strings (name of an individual),
  2217.  
  2218.  -  or integers (encoding of social security number as a pair of integers).
  2219.  
  2220. We then need a type containing both int * int and character strings.  We
  2221. also want to preserve static type-checking, we thus want to be able to
  2222. distinguish pairs from character strings even if they are injected in order
  2223. to form a single type.
  2224.   Here is what we would do:
  2225.  
  2226. #type identification = Name of string
  2227. #                    | SS of int * int;;
  2228. Type identification defined.
  2229.  
  2230. The type identification is the labeled disjoint union of string and
  2231. int * int.  The labels Name and SS are injections.  They respectively inject
  2232. int * int and string into a single type identification.
  2233.   Let us use these injections in order to build new values:
  2234.  
  2235. #let id1 = Name "Jean";;
  2236. id1 : identification = Name "Jean"
  2237.  
  2238. #let id2 = SS (1670728,280305);;
  2239. id2 : identification = SS (1670728, 280305)
  2240.  
  2241. Values id1 and id2 belong to the same type.  They may for example be put
  2242. into lists as in:
  2243.  
  2244. #[id1;id2];;
  2245. - : identification list = [Name "Jean"; SS (1670728, 280305)]
  2246.  
  2247.   Injections may possess one argument (as in the example above), or none.
  2248. The latter case corresponds(1) to enumerated types, as in Pascal.  An
  2249. example of enumerated type is:
  2250.  
  2251. ------------------------------
  2252.  1. In Caml Light, there is no implicit order on values of sum types.
  2253.  
  2254.  
  2255.  
  2256.                                      39
  2257.  
  2258.  
  2259.  
  2260. #type suit = Heart
  2261. #          | Diamond
  2262. #          | Club
  2263. #          | Spade;;
  2264. Type suit defined.
  2265.  
  2266. #Club;;
  2267. - : suit = Club
  2268.  
  2269. The type suit contains only 4 distinct elements.  Let us continue this
  2270. example by defining a type for cards.
  2271.  
  2272. #type card = Ace of suit
  2273. #          | King of suit
  2274. #          | Queen of suit
  2275. #          | Jack of suit
  2276. #          | Plain of suit * int;;
  2277. Type card defined.
  2278.  
  2279. The type card is the disjoint union of:
  2280.  
  2281.  -  suit under the injection Ace,
  2282.  
  2283.  -  suit under the injection King,
  2284.  
  2285.  -  suit under the injection Queen,
  2286.  
  2287.  -  suit under the injection Jack,
  2288.  
  2289.  -  the product of int and suit under the injection Plain.
  2290.  
  2291. Let us build a list of cards:
  2292.  
  2293. #let figures_of c = [Ace c; King c; Queen c; Jack c]
  2294. #and small_cards_of c =
  2295. #    map (function n -> Plain(c,n)) [7;8;9;10];;
  2296. figures_of : suit -> card list = <fun>
  2297. small_cards_of : suit -> card list = <fun>
  2298.  
  2299. #figures_of Heart;;
  2300. - : card list = [Ace Heart; King Heart; Queen Heart; Jack Heart]
  2301.  
  2302. #small_cards_of Spade;;
  2303. - : card list =
  2304.  [Plain (Spade, 7); Plain (Spade, 8); Plain (Spade, 9); Plain (Spade, 10)]
  2305.  
  2306.  
  2307. 6.2.2 Extracting sum components
  2308.  
  2309. Of course, pattern-matching is used to extract sum components.  In case of
  2310. sum types, pattern-matching uses dynamic tests for this extraction.  The
  2311.  
  2312.  
  2313.                                      40
  2314.  
  2315.  
  2316.  
  2317. next example defines a function color returning the name of the color of the
  2318. suit argument:
  2319.  
  2320. #let color = function Diamond -> "red"
  2321. #                   | Heart -> "red"
  2322. #                   | _ -> "black";;
  2323. color : suit -> string = <fun>
  2324.  
  2325. Let us count the values of cards (assume we are playing ``belote''):
  2326.  
  2327. #let count trump = function
  2328. #    Ace _        -> 11
  2329. #  | King _       -> 4
  2330. #  | Queen _      -> 3
  2331. #  | Jack c       -> if c = trump then 20 else 2
  2332. #  | Plain (c,10) -> 10
  2333. #  | Plain (c,9)  -> if c = trump then 14 else 0
  2334. #  | _             -> 0;;
  2335. count : suit -> card -> int = <fun>
  2336.  
  2337.  
  2338. 6.2.3 Recursive types
  2339.  
  2340. Some types possess a naturally recursive structure, lists, for example.  It
  2341. is also the case for tree-like structures, since trees have subtrees that
  2342. are trees themselves.
  2343.   Let us define a type for abstract syntax trees of a simple arithmetic
  2344. language(2).  An arithmetic expression will be either a numeric constant, or
  2345. a variable, or the addition, multiplication, difference, or division of two
  2346. expressions.
  2347.  
  2348. #type arith_expr = Const of int
  2349. #                | Var of string
  2350. #                | Plus of args
  2351. #                | Mult of args
  2352. #                | Minus of args
  2353. #                | Div of args
  2354. #and args = {Arg1:arith_expr; Arg2:arith_expr};;
  2355. Type arith_expr defined.
  2356. Type args defined.
  2357.  
  2358. The two types arith_expr and args are simultaneously defined, and arith_expr
  2359. is recursive since its definition refers to args which itself refers to
  2360. arith_expr.  As an example, one could represent the abstract syntax tree of
  2361. the arithmetic expression ``x+(3*y)'' as the Caml value:
  2362.  
  2363. ------------------------------
  2364.  2. Syntax trees are said to be abstract because they are pieces of abstract
  2365. syntax contrasting  with concrete  syntax which  is the  ``string'' form  of
  2366. programs:   analyzing (parsing)  concrete syntax  usually produces  abstract
  2367. syntax.
  2368.  
  2369.  
  2370.                                      41
  2371.  
  2372.  
  2373.  
  2374. #Plus {Arg1=Var "x";
  2375. #       Arg2=Mult{Arg1=Const 3; Arg2=Var "y"}};;
  2376. - : arith_expr = Plus {Arg1=Var "x"; Arg2=Mult {Arg1=Const 3; Arg2=Var "y"}}
  2377.  
  2378.   The recursive definition of types may lead to types such that it is hard
  2379. or impossible to build values of these types.  For example:
  2380.  
  2381. #type stupid = {Next:stupid};;
  2382. Type stupid defined.
  2383.  
  2384. Elements of this type are infinite data structures.  Essentially, the only
  2385. way to construct one is:
  2386.  
  2387. #let rec stupid_value = {Next=stupid_value};;
  2388. stupid_value : stupid =
  2389.  {Next=
  2390.    {Next=
  2391.      {Next=
  2392.        {Next=
  2393.          {Next=
  2394.            {Next=
  2395.              {Next=
  2396.                {Next=
  2397.                  {Next={Next={Next={Next={Next={Next={Next={Next=.}}}}}}}}}}}}}}
  2398. }}
  2399.  
  2400.   Recursive type definitions should be well-founded (i.e.  possess a
  2401. non-recursive case, or base case) in order to work well with call-by-value.
  2402.  
  2403. 6.2.4 Parameterized sum types
  2404.  
  2405. Sum types may also be parameterized.  Here is the definition of a type
  2406. isomorphic to the list type:
  2407.  
  2408. #type 'a sequence = Empty
  2409. #                 | Sequence of 'a * 'a sequence;;
  2410. Type sequence defined.
  2411.  
  2412.   A more sophisticated example is the type of generic binary trees:
  2413.  
  2414. #type ('a,'b) btree = Leaf of 'b
  2415. #                   | Btree of ('a,'b) node
  2416. #and ('a,'b) node = {Op:'a;
  2417. #                    Son1: ('a,'b) btree;
  2418. #                    Son2: ('a,'b) btree};;
  2419. Type btree defined.
  2420. Type node defined.
  2421.  
  2422. A binary tree is either a leaf (holding values of type 'b) or a node
  2423. composed of an operator (of type 'a) and two sons, both of them being binary
  2424. trees.
  2425.  
  2426.  
  2427.                                      42
  2428.  
  2429.  
  2430.  
  2431.   Binary trees can also be used to represent abstract trees for arithmetic
  2432. expressions (with only binary operators and only one kind of leaves).  The
  2433. abstract syntax tree t of ``1+2'' could be defined as:
  2434.  
  2435. #let t = Btree {Op="+"; Son1=Leaf 1; Son2=Leaf 2};;
  2436. t : (string, int) btree = Btree {Op="+"; Son1=Leaf 1; Son2=Leaf 2}
  2437.  
  2438.   Finally, it is time to notice that pattern-matching is not restricted to
  2439. function bodies, i.e.  constructs such as:
  2440.  
  2441.                            function  P1    -> E1
  2442.                                   |  .. .
  2443.                                   |  Pn    -> En
  2444.  
  2445. but there is also a construct dedicated to pattern-matching of actual
  2446. values:
  2447.  
  2448.                          match E with  P1    -> E1
  2449.                                     |  .. .
  2450.                                     |  Pn    -> En
  2451.  
  2452. which matches the value of the expression E against each of the patterns
  2453. Pi, selecting the first one that matches, and giving control to the
  2454. corresponding expression.  For example, we can match the tree t previously
  2455. defined by:
  2456.  
  2457. #match t with Btree{Op=x; Son1=_; Son2=_} -> x
  2458. #           | Leaf l -> "No operator";;
  2459. - : string = "+"
  2460.  
  2461.  
  2462. 6.2.5 Data constructors and functions
  2463.  
  2464. One may ask:  ``What is the difference between a sum data constructor and a
  2465. function?''.  At first sight, they look very similar.  We assimilate
  2466. constant data constructors (such as Heart) to constants.  Similarly, in Caml
  2467. Light, sum data constructors with arguments also possess a functional type:
  2468.  
  2469. #Ace;;
  2470. - : suit -> card = <fun>
  2471.  
  2472. However, a data constructor possesses particular properties that a general
  2473. function does not possess, and it is interesting to understand these
  2474. differences.  From the mathematical point of view, a sum data constructor is
  2475. known to be an injection while a Caml function is a general function without
  2476. further information.  A mathematical injection f:A->B admits an inverse
  2477. function f-1 from its image f(A)# B to A.
  2478.   From the examples above, if we consider the King constructor, then:
  2479.  
  2480. #let king c = King c;;
  2481. king : suit -> card = <fun>
  2482.  
  2483.  
  2484.                                      43
  2485.  
  2486.  
  2487.  
  2488. king is the general function associated to the King constructor, and:
  2489.  
  2490. #function King c -> c;;
  2491. Toplevel input:
  2492. >function King c -> c;;
  2493. >^^^^^^^^^^^^^^^^^^^^
  2494. Warning: this matching is not exhaustive.
  2495. - : card -> suit = <fun>
  2496.  
  2497. is the inverse function for king.  It is a partial function, since
  2498. pattern-matching may fail.
  2499.  
  2500. 6.2.6 Degenerate cases:  when sums meet products
  2501.  
  2502. What is the status of a sum type with a single case such as:
  2503.  
  2504. #type counter1 = Counter of int;;
  2505. Type counter1 defined.
  2506.  
  2507. Of course, the type counter1 is isomorphic to int.  The injection
  2508. function x -> Counter x is a total function from int to counter1.  It is
  2509. thus a bijection.
  2510.   Another way to define a type isomorphic to int would be:
  2511.  
  2512. #type counter2 = {Counter: int};;
  2513. Type counter2 defined.
  2514.  
  2515. The types counter1 and counter2 are isomorphic to int.  They are at the same
  2516. time sum and product types.  Their pattern-matching does not perform any
  2517. run-time test.
  2518.   The possibility of defining arbitrary complex data types permits the easy
  2519. manipulation of abstract syntax trees in Caml (such as the arith_expr type
  2520. above).  These abstract syntax trees are supposed to represent programs of a
  2521. language (e.g.  a language of arithmetic expressions).  These kind of
  2522. languages which are defined in Caml are called object-languages and Caml is
  2523. said to be their metalanguage.
  2524.  
  2525.  
  2526. 6.3 Summary
  2527.  
  2528.  -  New types can be introduced in Caml.
  2529.  
  2530.  -  Types may be parameterized by type variables.  The syntax of type
  2531.     parameters is:
  2532.  
  2533.  
  2534.     <params> ::
  2535.               | <tvar>
  2536.               | ( <tvar> [, <tvar>]* )
  2537.  
  2538.  
  2539.  
  2540.  
  2541.                                      44
  2542.  
  2543.  
  2544.  
  2545.  -  Types can be recursive.
  2546.  
  2547.  -  Product types:
  2548.  
  2549.  
  2550.      -  Mathematical product of several types.
  2551.  
  2552.      -  The construct is:
  2553.  
  2554.  
  2555.              type <params> <tname> =
  2556.                               {<Field>: <type>; ...}
  2557.  
  2558.  
  2559.  
  2560.         where the <type>s may contain type variables appearing in <params>.
  2561.  
  2562.  
  2563.  -  Sum types:
  2564.  
  2565.  
  2566.      -  Mathematical disjoint union of several types.
  2567.  
  2568.      -  The construct is:
  2569.  
  2570.  
  2571.              type <params> <tname> =
  2572.                       <Injection> [of <type>] | ...
  2573.  
  2574.  
  2575.  
  2576.         where the <type>s may contain type variables appearing in <params>.
  2577.  
  2578.  
  2579.  
  2580. Exercises
  2581.  
  2582. Exercise 6.1 Define a function taking as argument a binary tree and
  2583. returning a pair of lists:  the first one contains all operators of the
  2584. tree, the second one contains all its leaves.
  2585.  
  2586. Exercise 6.2 Define a function map_btree analogous to the map function on
  2587. lists.  The function map_btree should take as arguments two functions f and
  2588. g, and a binary tree.  It should return a new binary tree whose leaves are
  2589. the result of applying f to the leaves of the tree argument, and whose
  2590. operators are the results of applying the g function to the operators of the
  2591. argument.
  2592.  
  2593. Exercise 6.3 We can associate to the list type definition an canonical
  2594. iterator in the following way.  We give a functional interpretation to the
  2595. data constructors of the list type.
  2596.  
  2597.  
  2598.                                      45
  2599.  
  2600.  
  2601.  
  2602.   We change the list constructors [] and ::  respectively into a constant a
  2603. and an operator + (used as a prefix identifier), and abstract with respect
  2604. to these two operators, obtaining the list iterator satisfying:
  2605.  
  2606.     listit + a [] = a
  2607.     listit + a (x1::.. .::xn::[]) = x1 + (.. .+ (xn + a)... )
  2608.  
  2609. Its Caml definition would be:
  2610.  
  2611. #let rec list_it f a =
  2612. #        function [] -> a
  2613. #               | x::l -> f x (list_it f a l);;
  2614. list_it : ('a -> 'b -> 'b) -> 'b -> 'a list -> 'b = <fun>
  2615.  
  2616. As an example, the application of it_list to the functional composition and
  2617. to its neutral element (the identity function), computes the composition of
  2618. lists of functions (try it!).
  2619.   Define, using the same method, a canonical iterator over binary trees.
  2620.  
  2621.  
  2622.  
  2623.  
  2624.  
  2625.  
  2626.  
  2627.  
  2628.  
  2629.  
  2630.  
  2631.  
  2632.  
  2633.  
  2634.  
  2635.  
  2636.  
  2637.  
  2638.  
  2639.  
  2640.  
  2641.  
  2642.  
  2643.  
  2644.  
  2645.  
  2646.  
  2647.  
  2648.  
  2649.  
  2650.  
  2651.  
  2652.  
  2653.  
  2654.  
  2655.                                      46
  2656.  
  2657.  
  2658.  
  2659.  
  2660.  
  2661.  
  2662.  
  2663.  
  2664.  
  2665.  
  2666.  
  2667.  
  2668.  
  2669.  
  2670.  
  2671.  
  2672.  
  2673.  
  2674.  
  2675.  
  2676.                                   Part II
  2677.  
  2678.  
  2679.  
  2680.                             Caml Light specifics
  2681.  
  2682.  
  2683.  
  2684.  
  2685.  
  2686.  
  2687.  
  2688.  
  2689.  
  2690.  
  2691.  
  2692.  
  2693.  
  2694.  
  2695.  
  2696.  
  2697.  
  2698.  
  2699.  
  2700.  
  2701.  
  2702.  
  2703.  
  2704.  
  2705.  
  2706.  
  2707.  
  2708.  
  2709.  
  2710.  
  2711.  
  2712.                                      47
  2713.  
  2714.  
  2715.  
  2716.  
  2717.  
  2718.  
  2719.  
  2720.  
  2721.  
  2722. Chapter 7
  2723.  
  2724.  
  2725.  
  2726. Mutable data structures
  2727.  
  2728.  
  2729.  
  2730. The definition of a sum or product type may be annotated to allow physical
  2731. (destructive) update on data structures of that type.  This is the main
  2732. feature of the imperative programming style.  Writing values into memory
  2733. locations is the fundamental mechanism of imperative languages such as
  2734. Pascal.  The Lisp language, while mostly functional, also provides the
  2735. dangerous functions rplaca and rplacd to physically modify lists.  Mutable
  2736. structures are required to implement many efficient algorithms.  They are
  2737. also very convenient to represent the current state of a state machine.
  2738.  
  2739.  
  2740. 7.1 User-defined mutable data structures
  2741.  
  2742. Assume we want to define a type person as in the previous chapter.  Then, it
  2743. seems natural to allow a person to change his/her age, job and the city that
  2744. person lives in, but not his/her name.  We can do this by annotating some
  2745. labels in the type definition of person by the mutable keyword:
  2746.  
  2747. #type person =
  2748. #    {Name: string; mutable Age: int;
  2749. #     mutable Job: string; mutable City: string};;
  2750. Type person defined.
  2751.  
  2752. We can build values of type person in the very same way as before:
  2753.  
  2754. #let jean =
  2755. #    {Name="Jean"; Age=23; Job="Student"; City="Paris"};;
  2756. jean : person = {Name="Jean"; Age=23; Job="Student"; City="Paris"}
  2757.  
  2758. But now, the value jean may be physically modified in the fields specified
  2759. to be mutable in the definition (and only in these fields).
  2760.   We can modify the field Field of an expression <expr1> in order to assign
  2761. it the value of <expr2> by using the following construct:
  2762.  
  2763. <expr1>.Field <- <expr2>
  2764.  
  2765. For example; if we want jean to become one year older, we would write:
  2766.  
  2767.  
  2768.  
  2769.                                      48
  2770.  
  2771.  
  2772.  
  2773. #jean.Age <- jean.Age + 1;;
  2774. - : unit = ()
  2775.  
  2776. Now, the value jean has been modified into:
  2777.  
  2778. #jean;;
  2779. - : person = {Name="Jean"; Age=24; Job="Student"; City="Paris"}
  2780.  
  2781. We may try to change the Name of jean, but we won't succeed:  the typecheker
  2782. will not allow us to do that.
  2783.  
  2784. #jean.Name <- "Paul";;
  2785. Toplevel input:
  2786. >jean.Name <- "Paul";;
  2787. >^^^^^^^^^^^^^^^^^^^
  2788. The label Name is not mutable.
  2789.  
  2790. It is of course possible to use such constructs in functions as in:
  2791.  
  2792. #let get_older ({Age=n; _} as p) = p.Age <- n + 1;;
  2793. get_older : person -> unit = <fun>
  2794.  
  2795.  In that example, we named n the current Age of the argument, but we also
  2796. named p the argument.  This is an alias pattern:  it saves us the bother of
  2797. writing:
  2798.  
  2799. #let get_older p =
  2800. #    match p with {Age=n} -> p.Age <- n + 1;;
  2801. get_older : person -> unit = <fun>
  2802.  
  2803. Notice that in the two previous expressions, we did not specify all fields
  2804. of the record p.  Other examples would be:
  2805.  
  2806. #let move p new_city = p.City <- new_city
  2807. #and change_job p j = p.Job <- j;;
  2808. move : person -> string -> unit = <fun>
  2809. change_job : person -> string -> unit = <fun>
  2810.  
  2811. #change_job jean "Teacher"; move jean "Cannes";
  2812. #get_older jean; jean;;
  2813. - : person = {Name="Jean"; Age=25; Job="Teacher"; City="Cannes"}
  2814.  
  2815. We used the ``;'' character between the different changes we imposed to
  2816. jean.  This is the sequencing of evaluations:  it permits to evaluate
  2817. successively several expressions, discarding the result of each (except the
  2818. last one).  This construct becomes useful in the presence of side-effects
  2819. such as physical modifications and input/output, since we want to explicitly
  2820. specify the order in which they are performed.
  2821.  
  2822.  
  2823.  
  2824.  
  2825.  
  2826.                                      49
  2827.  
  2828.  
  2829.  
  2830. 7.2 The ref type
  2831.  
  2832. The ref type is the predefined type of mutable indirection cells.  It is
  2833. present in the Caml system for reasons of compatibility with earlier
  2834. versions of Caml.  The ref type could be defined as follows (we don't use
  2835. the ref name in the following definition because we want to preserve the
  2836. original ref type):
  2837.  
  2838. #type 'a reference = {mutable Ref: 'a};;
  2839. Type reference defined.
  2840.  
  2841. Example of building a value of type ref:
  2842.  
  2843. #let r = ref (1+2);;
  2844. r : int ref = ref 3
  2845.  
  2846. The ref identifier is syntactically presented as a sum data constructor.
  2847. The definition of r should be read as ``let r be a reference to the value of
  2848. 1+2''.  The value of r is nothing but a memory location whose contents can
  2849. be overwritten.
  2850.   We consult a reference (i.e.  read its memory location) with the ``!''
  2851. symbol:
  2852.  
  2853. #!r + 1;;
  2854. - : int = 4
  2855.  
  2856.   We modify values of type ref with the := infix function:
  2857.  
  2858. #r:=!r+1;;
  2859. - : unit = ()
  2860.  
  2861. #r;;
  2862. - : int ref = ref 4
  2863.  
  2864. Some primitives are attached to the ref type, for example:
  2865.  
  2866. #incr;;
  2867. - : int ref -> unit = <fun>
  2868.  
  2869. #decr;;
  2870. - : int ref -> unit = <fun>
  2871.  
  2872. which increments (resp.  decrements) references on integers.
  2873.  
  2874.  
  2875. 7.3 Arrays
  2876.  
  2877. Arrays are modifiable data structures.  They belong to the parameterized
  2878. type 'a vect.  Array expressions are bracketed by [| and |], and elements
  2879. are separated by semicolons:
  2880.  
  2881.  
  2882.  
  2883.                                      50
  2884.  
  2885.  
  2886.  
  2887. #let a = [| 10; 20; 30 |];;
  2888. a : int vect = [|10; 20; 30|]
  2889.  
  2890. The length of an array is returned by with the function vect_length:
  2891.  
  2892. #vect_length a;;
  2893. - : int = 3
  2894.  
  2895.  
  2896. 7.3.1 Accessing array elements
  2897.  
  2898. Accesses to array elements can be done using the following syntax:
  2899.  
  2900. #a.(0);;
  2901. - : int = 10
  2902.  
  2903. or, more generally:  e1.(e2), where e1 evaluates to an array and e2 to an
  2904. integer.  Alternatively, the function vect_item is provided:
  2905.  
  2906. #vect_item;;
  2907. - : 'a vect -> int -> 'a = <fun>
  2908.  
  2909. The first element of an array is at index 0.  Arrays are useful because
  2910. accessing an element is done in constant time:  an array is a contiguous
  2911. fragment of memory, while accessing list elements takes linear time.
  2912.  
  2913. 7.3.2 Modifying array elements
  2914.  
  2915. Modification of an array element is done with the construct:
  2916.  
  2917.                                e1.(e2) <- e3
  2918.  
  2919. where e3 has the same type as the elements of the array e1.  The expression
  2920. e2 computes the index at which the modification will occur.
  2921.   As for accessing, a function for modifying array elements is also
  2922. provided:
  2923.  
  2924. #vect_assign;;
  2925. - : 'a vect -> int -> 'a -> unit = <fun>
  2926.  
  2927. For example:
  2928.  
  2929. #a.(0) <- (a.(0)-1);;
  2930. - : unit = ()
  2931.  
  2932. #a;;
  2933. - : int vect = [|9; 20; 30|]
  2934.  
  2935. #vect_assign a 0 ((vect_item a 0) - 1);;
  2936. - : unit = ()
  2937.  
  2938.  
  2939.  
  2940.                                      51
  2941.  
  2942.  
  2943.  
  2944. #a;;
  2945. - : int vect = [|8; 20; 30|]
  2946.  
  2947.  
  2948.  
  2949. 7.4 Loops:  while and for
  2950.  
  2951. Imperative programming (i.e.  using side-effects such as physical
  2952. modification of data structures) traditionally makes use of sequences and
  2953. explicit loops.  Sequencing evaluation in Caml Light is done by using the
  2954. semicolon ``;''.  Evaluating expression e1, discarding the value returned,
  2955. and then evaluating e2 is written:
  2956.  
  2957.                                   e1 ; e2
  2958.  
  2959. If e1 and e2 perform side-effects, this construct ensures that they will be
  2960. performed in the specified order (from left to right).  In order to
  2961. emphasize sequential side-effects, instead of using parentheses around
  2962. sequences, one can use begin and end, as in:
  2963.  
  2964. #let x = ref 1 in
  2965. #  begin
  2966. #     x := !x + 1;
  2967. #     x := !x * !x
  2968. #  end;;
  2969. - : unit = ()
  2970.  
  2971. The keywords begin and end are equivalent to opening and closing
  2972. parentheses.  The program above could be written as:
  2973.  
  2974. #let x = ref 1 in
  2975. #  (x := !x + 1; x := !x * !x);;
  2976. - : unit = ()
  2977.  
  2978.   Explicit loops are not strictly necessary per se:  a recursive function
  2979. could perform the same work.  However, the usage of an explicit loop locally
  2980. emphasizes a more imperative style.  Two loops are provided:
  2981.  
  2982.  -  while:  while e1 do e2 done evaluates e1 which must return a boolean
  2983.     expression, if e1 return true, then e2 (which is usually a sequence) is
  2984.     evaluated, then e1 is evaluated again and so on until e1 returns false.
  2985.  
  2986.  -  for:  two variants, increasing and decreasing
  2987.  
  2988.  
  2989.      -  for v=e1 to e2 do e3 done
  2990.  
  2991.      -  for v=e1 downto e2 do e3 done
  2992.  
  2993.  
  2994.  
  2995.  
  2996.  
  2997.                                      52
  2998.  
  2999.  
  3000.  
  3001.     where v is an identifier.  Expressions e1 and e2 are the bounds of the
  3002.     loop:  they must evaluate to integers.  In the case of the increasing
  3003.     loop, the expressions e1 and e2 are evaluated producing values n1 and
  3004.     n2 :  if n1 is strictly greater than n2, then nothing is done.
  3005.     Otherwise, e3 is evaluated (n2-n1 )+1 times, with the variable v bound
  3006.     successively to n1, n1+1, . .., n2.
  3007.  
  3008.     The behavior of the decreasing loop is similar:  if n1 is strictly
  3009.     smaller than n2, then nothing is done.  Otherwise, e3 is evaluated
  3010.     (n1-n2) +1 times with v bound to successive values decreasing from n1
  3011.     to n2.
  3012.  
  3013. Both loops return the value () of type unit.
  3014.  
  3015. #for i=0 to (vect_length a) - 1 do a.(i) <- i done;;
  3016. - : unit = ()
  3017.  
  3018. #a;;
  3019. - : int vect = [|0; 1; 2|]
  3020.  
  3021.  
  3022.  
  3023. 7.5 Polymorphism and mutable data structures
  3024.  
  3025. There are some restrictions concerning polymorphism and mutable data
  3026. structures.  One cannot enclose polymorphic objects inside mutable data
  3027. structures.
  3028.  
  3029. #let r = ref [];;
  3030. r : '_a list ref = ref []
  3031.  
  3032. The reason is that once the type of r, ('a list) ref, has been computed, it
  3033. cannot be changed.  But the value of r can be changed:  we could write:
  3034.  
  3035. r:=[1;2];;
  3036.  
  3037. and now, r would be a reference on a list of numbers while its type would
  3038. still be ('a list) ref, allowing us to write:
  3039.  
  3040. r:= true::!r;;
  3041.  
  3042. making r a reference on [true; 1; 2], which is an illegal Caml object.
  3043.   Thus the Caml typechecker imposes that modifiable data structures
  3044. appearing at toplevel must possess monomorphic types (i.e.  not
  3045. polymorphic).
  3046.  
  3047.  
  3048. Exercises
  3049.  
  3050. Exercise 7.1 Give a mutable data type defining the Lisp type of lists and
  3051. define the four functions car, cdr, rplaca and rplacd.
  3052.  
  3053.  
  3054.  
  3055.                                      53
  3056.  
  3057.  
  3058.  
  3059. Exercise 7.2 Define a stamp function, of type unit -> int, that returns a
  3060. fresh integer each time it is called.  That is, the first call returns 1;
  3061. the second call returns 2; and so on.
  3062.  
  3063. Exercise 7.3 Define a quick_sort function on arrays of floating point
  3064. numbers following the quicksort algorithm [13].  Information about the
  3065. quicksort algorithm can be found in [33], for example.
  3066.  
  3067.  
  3068.  
  3069.  
  3070.  
  3071.  
  3072.  
  3073.  
  3074.  
  3075.  
  3076.  
  3077.  
  3078.  
  3079.  
  3080.  
  3081.  
  3082.  
  3083.  
  3084.  
  3085.  
  3086.  
  3087.  
  3088.  
  3089.  
  3090.  
  3091.  
  3092.  
  3093.  
  3094.  
  3095.  
  3096.  
  3097.  
  3098.  
  3099.  
  3100.  
  3101.  
  3102.  
  3103.  
  3104.  
  3105.  
  3106.  
  3107.  
  3108.  
  3109.  
  3110.  
  3111.  
  3112.                                      54
  3113.  
  3114.  
  3115.  
  3116.  
  3117.  
  3118.  
  3119.  
  3120.  
  3121.  
  3122. Chapter 8
  3123.  
  3124.  
  3125.  
  3126. Escaping from computations:  exceptions
  3127.  
  3128.  
  3129.  
  3130. In some situations, it is necessary to abort computations.  If we are trying
  3131. to compute the integer division of an integer n by 0, then we must escape
  3132. from that embarrassing situation without returning any result.
  3133.   Another example of the usage of such an escape mechanism appears when we
  3134. want to define the head function on lists:
  3135.  
  3136. #let head = function
  3137. #     x::L -> x
  3138. #   | [] -> raise (Failure "head: empty list");;
  3139. Toplevel input:
  3140. >     x::L -> x
  3141. >        ^
  3142. Warning: the variable L starts with an upper case letter in this pattern.
  3143. head : 'a list -> 'a = <fun>
  3144.  
  3145. We cannot give a regular value to the expression head [] without losing the
  3146. polymorphism of head.  We thus choose to escape:  we raise an exception.
  3147.  
  3148.  
  3149. 8.1 Exceptions
  3150.  
  3151. An exception is a Caml value of the built-in type exn, very similar to a sum
  3152. type.  An exception:
  3153.  
  3154.  -  has a name (Failure in our example),
  3155.  
  3156.  -  and holds zero or one value ("head:  empty list" of type string in the
  3157.     example).
  3158.  
  3159.   Some exceptions are predefined, like Failure.  New exceptions can be
  3160. defined with the following construct:
  3161.  
  3162. exception <exception name> [of <type>]
  3163.  
  3164.   Example:
  3165.  
  3166. #exception Found of int;;
  3167.  
  3168.  
  3169.                                      55
  3170.  
  3171.  
  3172.  
  3173. Exception Found defined.
  3174.  
  3175. The exception Found has been declared, and it carries integer values.  When
  3176. we apply it to an integer, we get an exception value (of type exn):
  3177.  
  3178. #Found 5;;
  3179. - : exn = Found 5
  3180.  
  3181.  
  3182.  
  3183. 8.2 Raising an exception
  3184.  
  3185. Raising an exception is done by applying the primitive function raise to a
  3186. value of type exn:
  3187.  
  3188. #raise;;
  3189. - : exn -> 'a = <fun>
  3190.  
  3191. #raise (Found 5);;
  3192. Uncaught exception: Found 5
  3193.  
  3194. Here is a more realistic example:
  3195.  
  3196. #let find_index p =
  3197. #  let rec find n =
  3198. #    function [] -> raise (Failure "not found")
  3199. #           | x::L -> if p(x) then raise (Found n)
  3200. #                     else find (n+1) L
  3201. #  in find 1;;
  3202. Toplevel input:
  3203. >           | x::L -> if p(x) then raise (Found n)
  3204. >                ^
  3205. Warning: the variable L starts with an upper case letter in this pattern.
  3206. find_index : ('a -> bool) -> 'a list -> 'b = <fun>
  3207.  
  3208. The find_index function always fails.  It raises:
  3209.  
  3210.  -  Found n, if there is an element x of the list such that p(x), in this
  3211.     case n is the index of x in the list,
  3212.  
  3213.  -  the Failure exception if no such x has been found.
  3214.  
  3215. Raising exceptions is more than an error mechanism:  it is a programmable
  3216. control structure.  In the find_index example, there was no error when
  3217. raising the Found exception:  we only wanted to quickly escape from the
  3218. computation, since we found what we were looking for.  This is why it must
  3219. be possible to trap exceptions:  we want to trap possible errors, but we
  3220. also want to get our result in the case of the find_index function.
  3221.  
  3222.  
  3223.  
  3224.  
  3225.  
  3226.                                      56
  3227.  
  3228.  
  3229.  
  3230. 8.3 Trapping exceptions
  3231.  
  3232. Trapping exceptions is achieved by the following construct:
  3233.  
  3234. try <expression> with <match cases>
  3235.  
  3236.   This construct evaluates <expression>.  If no exception is raised during
  3237. the evaluation, then the result of the try construct is the result of
  3238. <expression>.  If an exception is raised during this evaluation, then the
  3239. raised exception is matched against the <match cases>.  If a case matches,
  3240. then control is passed to it.  If no case matches, then the exception is
  3241. propagated outside of the try construct, looking for the enclosing try.
  3242.   Example:
  3243.  
  3244. #let find_index p L =
  3245. #  let rec find n =
  3246. #    function [] -> raise (Failure "not found")
  3247. #           | x::L -> if p(x) then raise (Found n)
  3248. #                     else find (n+1) L
  3249. #  in
  3250. #    try find 1 L with Found n -> n;;
  3251. Toplevel input:
  3252. >let find_index p L =
  3253. >                 ^
  3254. Warning: the variable L starts with an upper case letter in this pattern.
  3255. Toplevel input:
  3256. >           | x::L -> if p(x) then raise (Found n)
  3257. >                ^
  3258. Warning: the variable L starts with an upper case letter in this pattern.
  3259. find_index : ('a -> bool) -> 'a list -> int = <fun>
  3260.  
  3261. #find_index (function n -> (n mod 2) = 0) [1;3;5;7;9;10];;
  3262. - : int = 6
  3263.  
  3264. #find_index (function n -> (n mod 2) = 0) [1;3;5;7;9];;
  3265. Uncaught exception: Failure "not found"
  3266.  
  3267. The <match cases> part of the try construct is a regular pattern matching on
  3268. values of type exn.  It is thus possible to trap any exception by using the
  3269. _ symbol.  As an example, the following function traps any exception raised
  3270. during the application of its two arguments.  Warning:  the _ will also trap
  3271. interrupts from the keyboard such as control-C!
  3272.  
  3273. #let catch_all f arg default =
  3274. #       try f(arg) with _ -> default;;
  3275. catch_all : ('a -> 'b) -> 'a -> 'b -> 'b = <fun>
  3276.  
  3277. It is even possible to catch all exceptions, do something special (close or
  3278. remove opened files, for example), and raise again that exception, to
  3279. propagate it upwards.
  3280.  
  3281.  
  3282.  
  3283.                                      57
  3284.  
  3285.  
  3286.  
  3287. #let show_exceptions f arg =
  3288. #        try f(arg) with x -> print_string "Exception raised!\n"; raise x;;
  3289. show_exceptions : ('a -> 'b) -> 'a -> 'b = <fun>
  3290.  
  3291. In the example above, we print a message to the standard output channel (the
  3292. terminal), before raising again the trapped exception.
  3293.  
  3294. #catch_all (function x -> raise (Failure "foo")) 1 0;;
  3295. - : int = 0
  3296.  
  3297. #catch_all (show_exceptions (function x -> raise (Failure "foo"))) 1 0;;
  3298. Exception raised!
  3299. - : int = 0
  3300.  
  3301.  
  3302.  
  3303. 8.4 Polymorphism and exceptions
  3304.  
  3305. Exceptions must not be polymorphic for a reason similar to the one for
  3306. references (although it is a bit harder to give an example).
  3307.  
  3308. #exception Exc of 'a list;;
  3309. Toplevel input:
  3310. >exception Exc of 'a list;;
  3311. >                 ^^
  3312. The type variable a is unbound.
  3313.  
  3314. One reason is that the excn type is not a parameterized type, but one deeper
  3315. reason is that if the exception Exc is declared to be polymorphic, then a
  3316. function may raise Exc [1;2].  There might be no mention of that fact in the
  3317. type inferred for the function.  Then, another function may trap that
  3318. exception, obtaining the value [1;2] whose real type is int list.  But the
  3319. only type known by the typechecker is 'a list:  the try form should refer to
  3320. the Exc data constructor, which is known to be polymorphic.  It may then be
  3321. possible to build an ill-typed Caml value [true; 1; 2], since the
  3322. typechecker does not possess any further type information than 'a list.
  3323.   The problem is thus the absence of static connection from exceptions that
  3324. are raised and the occurrences where they are trapped.  Another example
  3325. would be the one of a function raising Exc with an integer or a boolean
  3326. value, depending on some condition.  Then, in that case, when trying to trap
  3327. these exceptions, we cannot decide wether they will hold integers or boolean
  3328. values.
  3329.  
  3330.  
  3331. Exercises
  3332.  
  3333. Exercise 8.1 Define the function find_succeed which given a function f and
  3334. a list L returns the first element of L on which the application of f
  3335. succeeds.
  3336.  
  3337. Exercise 8.2 Define the function map_succeed which given a function f and a
  3338. list L returns the list of the results of successful applications of f to
  3339.  
  3340.  
  3341.                                      58
  3342.  
  3343.  
  3344.  
  3345. elements of L.
  3346.  
  3347.  
  3348.  
  3349.  
  3350.  
  3351.  
  3352.  
  3353.  
  3354.  
  3355.  
  3356.  
  3357.  
  3358.  
  3359.  
  3360.  
  3361.  
  3362.  
  3363.  
  3364.  
  3365.  
  3366.  
  3367.  
  3368.  
  3369.  
  3370.  
  3371.  
  3372.  
  3373.  
  3374.  
  3375.  
  3376.  
  3377.  
  3378.  
  3379.  
  3380.  
  3381.  
  3382.  
  3383.  
  3384.  
  3385.  
  3386.  
  3387.  
  3388.  
  3389.  
  3390.  
  3391.  
  3392.  
  3393.  
  3394.  
  3395.  
  3396.  
  3397.  
  3398.                                      59
  3399.  
  3400.  
  3401.  
  3402.  
  3403.  
  3404.  
  3405.  
  3406.  
  3407.  
  3408. Chapter 9
  3409.  
  3410.  
  3411.  
  3412. Basic input/output
  3413.  
  3414.  
  3415.  
  3416. We describe in this chapter the Caml Light input/output model and some of
  3417. its primitive operations.  More complete information about IO can be found
  3418. in the Caml Light manual [20].
  3419.   Caml Light has an imperative input/output model:  an IO operation should
  3420. be considered as a side-effect, and is thus dependent on the order of
  3421. evaluation.  IOs are performed onto channels with types in_channel and
  3422. out_channel.  These types are abstract, i.e.  their representation is not
  3423. accessible.
  3424.   Three channels are predefined:
  3425.  
  3426. #std_in;;
  3427. - : in_channel = <abstr>
  3428.  
  3429. #std_out;;
  3430. - : out_channel = <abstr>
  3431.  
  3432. #std_err;;
  3433. - : out_channel = <abstr>
  3434.  
  3435. They are the ``standard'' IO channels:  std_in is usually connected to the
  3436. keyboard, and printing onto std_out and std_err usually appears on the
  3437. screen.
  3438.  
  3439.  
  3440. 9.1 Printable types
  3441.  
  3442. It is not possible to print and read every value.  Functions, for example,
  3443. are typically not readable, unless a suitable string representation is
  3444. designed and reading such a representation is followed by an interpretation
  3445. computing the desired function.
  3446.   We call printable type a type for which there are input/output primitives
  3447. implemented in Caml Light.  The main printable types are:
  3448.  
  3449.  -  characters:  type char;
  3450.  
  3451.  -  strings:  type string;
  3452.  
  3453.  
  3454.  
  3455.                                      60
  3456.  
  3457.  
  3458.  
  3459.  -  integers:  type int;
  3460.  
  3461.  -  floating point numbers:  type float.
  3462.  
  3463. We know all these types from the previous chapters.  Strings and characters
  3464. support a notation for escaping to ASCII codes or to denote special
  3465. characters such as newline:
  3466.  
  3467. #`A`;;
  3468. - : char = `A`
  3469.  
  3470. #`\065`;;
  3471. - : char = `A`
  3472.  
  3473. #`\\`;;
  3474. - : char = `\\`
  3475.  
  3476. #`\n`;;
  3477. - : char = `\n`
  3478.  
  3479. #"string with\na newline inside";;
  3480. - : string = "string with\na newline inside"
  3481.  
  3482. The ``\'' character is used as an escape and is useful for non-printable or
  3483. special characters.
  3484.   Of course, character constants can be used as constant patterns:
  3485.  
  3486. #function `a` -> 0 | _ -> 1;;
  3487. - : char -> int = <fun>
  3488.  
  3489. On types such as char that have a finite number of constant elements, it may
  3490. be useful to use or-patterns, gathering constants in the same matching rule:
  3491.  
  3492. #let is_vowel = function
  3493. #  `a` | `e` | `i` | `o` | `u` | `y` -> true
  3494. #| _ -> false;;
  3495. is_vowel : char -> bool = <fun>
  3496.  
  3497. The first rule is chosen if the argument matches one of the cases.  Since
  3498. there is a total ordering on characters, the syntax of character patterns is
  3499. enriched with a ``..'' notation:
  3500.  
  3501. #let is_lower_case_letter = function
  3502. #  `a`..`z` -> true
  3503. #| _ -> false;;
  3504. is_lower_case_letter : char -> bool = <fun>
  3505.  
  3506. Of course, or-patterns and this notation can be mixed, as in:
  3507.  
  3508. #let is_letter = function
  3509. #  `a`..`z` | `A`..`Z` -> true
  3510.  
  3511.  
  3512.                                      61
  3513.  
  3514.  
  3515.  
  3516. #| _ -> false;;
  3517. is_letter : char -> bool = <fun>
  3518.  
  3519.   In the next sections, we give the most commonly used IO primitives on
  3520. these printable types.  A complete listing of predefined IO operations is
  3521. given in [20].
  3522.  
  3523.  
  3524. 9.2 Output
  3525.  
  3526. Printing on standard output is performed by the following functions:
  3527.  
  3528. #print_char;;
  3529. - : char -> unit = <fun>
  3530.  
  3531. #print_string;;
  3532. - : string -> unit = <fun>
  3533.  
  3534. #print_int;;
  3535. - : int -> unit = <fun>
  3536.  
  3537. #print_float;;
  3538. - : float -> unit = <fun>
  3539.  
  3540. Printing is buffered, i.e.  the effect of a call to a printing function may
  3541. not be seen immediately:  flushing explicitly the output buffer is sometimes
  3542. required, unless a printing function flushes it implicitly.  Flushing is
  3543. done with the flush function:
  3544.  
  3545. #flush;;
  3546. - : out_channel -> unit = <fun>
  3547.  
  3548. #print_string "Hello!"; flush std_out;;
  3549. Hello!- : unit = ()
  3550.  
  3551. The print_newline function prints a newline character and flushes the
  3552. standard output:
  3553.  
  3554. #print_newline;;
  3555. - : unit -> unit = <fun>
  3556.  
  3557. Flushing is required when writing standalone applications, in which the
  3558. application may terminate without all printing being done.  Standalone
  3559. applications should terminate by a call to the exit function (from the io
  3560. module), which flushes all pending output on std_out and std_err.
  3561.   Printing on the standard error channel std_err is done with the following
  3562. functions:
  3563.  
  3564. #prerr_char;;
  3565. - : char -> unit = <fun>
  3566.  
  3567.  
  3568.  
  3569.                                      62
  3570.  
  3571.  
  3572.  
  3573. #prerr_string;;
  3574. - : string -> unit = <fun>
  3575.  
  3576. #prerr_int;;
  3577. - : int -> unit = <fun>
  3578.  
  3579. #prerr_float;;
  3580. - : float -> unit = <fun>
  3581.  
  3582. The following function prints its string argument followed by a newline
  3583. character to std_err and then flushes std_err.
  3584.  
  3585. #prerr_endline;;
  3586. - : string -> unit = <fun>
  3587.  
  3588.  
  3589.  
  3590. 9.3 Input
  3591.  
  3592. These input primitives flush the standard output and read from the standard
  3593. input:
  3594.  
  3595. #read_line;;
  3596. - : unit -> string = <fun>
  3597.  
  3598. #read_int;;
  3599. - : unit -> int = <fun>
  3600.  
  3601. #read_float;;
  3602. - : unit -> float = <fun>
  3603.  
  3604. Because of their names and types, these functions do not need further
  3605. explanation.
  3606.  
  3607.  
  3608. 9.4 Channels on files
  3609.  
  3610. When programs have to read from or print to files, it is necessary to open
  3611. and close channels on these files.
  3612.  
  3613. 9.4.1 Opening and closing channels
  3614.  
  3615. Opening and closing is performed with the following functions:
  3616.  
  3617. #open_in;;
  3618. - : string -> in_channel = <fun>
  3619.  
  3620. #open_out;;
  3621. - : string -> out_channel = <fun>
  3622.  
  3623. #close_in;;
  3624. - : in_channel -> unit = <fun>
  3625.  
  3626.  
  3627.                                      63
  3628.  
  3629.  
  3630.  
  3631. #close_out;;
  3632. - : out_channel -> unit = <fun>
  3633.  
  3634. The open_in function checks the existence of its filename argument, and
  3635. returns a new input channel on that file; open_out creates a new file (or
  3636. truncates it to zero length if it exists) and returns an output channel on
  3637. that file.  Both functions fail if permissions are not sufficient for
  3638. reading or writing.
  3639. Warning:
  3640.  
  3641.  -  Closing functions close their channel argument.  Since their behavior is
  3642.     unspecified on already closed channels, anything can happen in this
  3643.     case!
  3644.  
  3645.  -  Closing one of the standard IO channels (std_in, std_out, std_err) have
  3646.     unpredictable effects!
  3647.  
  3648. 9.4.2 Reading or writing from/to specified channels
  3649.  
  3650. Some of the functions on standard input/output have corresponding functions
  3651. working on channels:
  3652.  
  3653. #output_char;;
  3654. - : out_channel -> char -> unit = <fun>
  3655.  
  3656. #output_string;;
  3657. - : out_channel -> string -> unit = <fun>
  3658.  
  3659. #input_char;;
  3660. - : in_channel -> char = <fun>
  3661.  
  3662. #input_line;;
  3663. - : in_channel -> string = <fun>
  3664.  
  3665.  
  3666. 9.4.3 Failures
  3667.  
  3668. The exception End_of_file is raised when an input operation cannot complete
  3669. because the end of the file has been reached.
  3670.  
  3671. #End_of_file;;
  3672. - : exn = End_of_file
  3673.  
  3674.   The exception sys__Sys_error (Sys_error from the module sys) is raised
  3675. when some manipulation of files is forbidden by the operating system:
  3676.  
  3677. #open_in "abracadabra";;
  3678. Uncaught exception: sys__Sys_error "abracadabra: No such file or directory"
  3679.  
  3680.   The functions that we have seen in this chapter are sufficient for our
  3681. needs.  Many more exist (useful mainly when working with files) and are
  3682.  
  3683.  
  3684.                                      64
  3685.  
  3686.  
  3687.  
  3688. described in [20].
  3689.  
  3690.  
  3691. Exercises
  3692.  
  3693. Exercise 9.1 Define a function copy_file taking two filenames (of type
  3694. string) as arguments, and copying the contents of the first file on the
  3695. second one.  Error messages must be printed on std_err.
  3696.  
  3697. Exercise 9.2 Define a function wc taking a filename as argument and
  3698. printing on the standard output the number of characters and lines appearing
  3699. in the file.  Error messages must be printed on std_err.
  3700.  
  3701. Note:  it is good practice to develop a program in defining small functions.
  3702. A single function doing the whole work is usually harder to debug and to
  3703. read.  With small functions, one can trace them and see the arguments they
  3704. are called on and the result they produce.
  3705.  
  3706.  
  3707.  
  3708.  
  3709.  
  3710.  
  3711.  
  3712.  
  3713.  
  3714.  
  3715.  
  3716.  
  3717.  
  3718.  
  3719.  
  3720.  
  3721.  
  3722.  
  3723.  
  3724.  
  3725.  
  3726.  
  3727.  
  3728.  
  3729.  
  3730.  
  3731.  
  3732.  
  3733.  
  3734.  
  3735.  
  3736.  
  3737.  
  3738.  
  3739.  
  3740.  
  3741.                                      65
  3742.  
  3743.  
  3744.  
  3745.  
  3746.  
  3747.  
  3748.  
  3749.  
  3750.  
  3751. Chapter 10
  3752.  
  3753.  
  3754.  
  3755. Streams and parsers
  3756.  
  3757.  
  3758.  
  3759. In the next part of these course notes, we will implement a small functional
  3760. language.  Parsing valid programs of this language requires writing a
  3761. lexical analyzer and a parser for the language.  For the purpose of writing
  3762. easily such programs, Caml Light provides a special data structure:
  3763. streams.  Their main usage is to be interfaced to input channels or strings
  3764. and to be matched against stream patterns.
  3765.  
  3766.  
  3767. 10.1 Streams
  3768.  
  3769. Streams belong to an abstract data type:  their actual representation
  3770. remains hidden from the user.  However, it is still possible to build
  3771. streams either ``by hand'' or by using some predefined functions.
  3772.  
  3773. 10.1.1 The stream type
  3774.  
  3775. The type stream is a parameterized type.  One can build streams of integers,
  3776. of characters or of any other type.  Streams receive a special syntax,
  3777. looking like the one for lists.  The empty stream is written:
  3778.  
  3779. #[< >];;
  3780. - : '_a stream = <abstr>
  3781.  
  3782. A non empty stream possesses elements that are written preceded by the ``'''
  3783. (quote) character.
  3784.  
  3785. #[< '0; '1; '2 >];;
  3786. - : int stream = <abstr>
  3787.  
  3788. Elements that are not preceded by ``''' are substreams that are expanded in
  3789. the enclosing stream:
  3790.  
  3791. #[< '0; [<'1;'2>]; '3 >];;
  3792. - : int stream = <abstr>
  3793.  
  3794. #let s = [< '"abc" >] in [< s; '"def" >];;
  3795.  
  3796.  
  3797.                                      66
  3798.  
  3799.  
  3800.  
  3801. - : string stream = <abstr>
  3802.  
  3803. Thus, stream concatenation can be defined as:
  3804.  
  3805. #let stream_concat s t = [< s; t >];;
  3806. stream_concat : 'a stream -> 'a stream -> 'a stream = <fun>
  3807.  
  3808. Building streams in this way can be useful while testing a parsing function
  3809. or defining a lexical analyzer (taking as argument a stream of characters
  3810. and returning a stream of tokens).  Stream concatenation does not copy
  3811. substreams:  they are simply put in the same stream.  Since (as we will see
  3812. later) stream matching has a destructive effect on streams (streams are
  3813. physically ``eaten'' by stream matching), parsing [< t; t >] will in fact
  3814. parse t only once:  the first occurrence of t will be consumed, and the
  3815. second occurrence will be empty before its parsing will be performed.
  3816.   Interfacing streams with an input channel can be done with the function:
  3817.  
  3818. #stream_of_channel;;
  3819. - : in_channel -> char stream = <fun>
  3820.  
  3821. returning a stream of characters which are read from the channel argument.
  3822. The end of stream will coincide with the end of the file associated to the
  3823. channel.
  3824.   In the same way, one can build the character stream associated to a
  3825. character string using:
  3826.  
  3827. #stream_of_string;;
  3828. - : string -> char stream = <fun>
  3829.  
  3830. #let s = stream_of_string "abc";;
  3831. s : char stream = <abstr>
  3832.  
  3833.  
  3834. 10.1.2 Streams are lazily evaluated
  3835.  
  3836. Stream expressions are submitted to lazy evaluation, i.e.  they are
  3837. effectively build only when required.  This is useful in that it allows for
  3838. the easy manipulation of ``interactive'' streams like the stream built from
  3839. the standard input.  If this was not the case, i.e.  if streams were
  3840. immediately completely computed, a program evaluating
  3841. ``stream_of_channel std_in'' would read everything up to an end-of-file on
  3842. standard input before giving control to the rest of the program.
  3843. Furthermore, lazy evaluation of streams allows for the manipulation of
  3844. infinite streams.  As an example, we can build the infinite stream of
  3845. integers, using side effects to show precisely when computations occur:
  3846.  
  3847. #let rec ints_from n =
  3848. #   [< '(print_int n; print_char ` `; flush std_out; n);
  3849. #      ints_from (n+1) >];;
  3850. ints_from : int -> int stream = <fun>
  3851.  
  3852.  
  3853.  
  3854.                                      67
  3855.  
  3856.  
  3857.  
  3858. #let ints = ints_from 0;;
  3859. ints : int stream = <abstr>
  3860.  
  3861. We notice that no printing occurred and that the program terminates:  this
  3862. shows that none of the elements have been evaluated and that the infinite
  3863. stream has not been built.  We will see in the next section that these
  3864. side-effects will occur on demand, i.e.  when tests will be needed by a
  3865. matching function on streams.
  3866.  
  3867.  
  3868. 10.2 Stream matching and parsers
  3869.  
  3870. The syntax for building streams can be used for pattern-matching over them.
  3871. However, stream matching is more complex than the usual pattern matching.
  3872.  
  3873. 10.2.1 Stream matching is destructive
  3874.  
  3875. Let us start with a simple example:
  3876.  
  3877. #let next = function [< 'x >] -> x;;
  3878. next : 'a stream -> 'a = <fun>
  3879.  
  3880. The next function returns the first element of its stream argument, and
  3881. fails if the stream is empty:
  3882.  
  3883. #let s = [< '0; '1; '2 >];;
  3884. s : int stream = <abstr>
  3885.  
  3886. #next s;;
  3887. - : int = 0
  3888.  
  3889. #next s;;
  3890. - : int = 1
  3891.  
  3892. #next s;;
  3893. - : int = 2
  3894.  
  3895. #next s;;
  3896. Uncaught exception: Parse_failure
  3897.  
  3898. We can see from the previous examples that the stream pattern [< 'x >]
  3899. matches an initial segment of the stream.  Such a pattern must be read as
  3900. ``the stream whose first element matches x''.  Furthermore, once stream
  3901. matching has succeeded, the stream argument has been physically modified and
  3902. does not contain any longer the part that has been recognized by the next
  3903. function.
  3904.   If we come back to the infinite stream of integers, we can see that the
  3905. calls to next provoke the evaluation of the necessary part of the stream:
  3906.  
  3907. #next ints; next ints; next ints;;
  3908. 0 1 2 - : int = 2
  3909.  
  3910.  
  3911.                                      68
  3912.  
  3913.  
  3914.  
  3915. Thus, successive calls to next remove the first elements of the stream until
  3916. it becomes empty.  Then, next fails when applied to the empty stream, since,
  3917. in the definition of next, there is no stream pattern that matches an
  3918. initial segment of the empty stream.
  3919.   It is of course possible to specify several stream patterns as in:
  3920.  
  3921. #let next = function
  3922. #  [< 'x >] -> x
  3923. #| [< >] -> raise (Failure "empty");;
  3924. next : 'a stream -> 'a = <fun>
  3925.  
  3926. Cases are tried in turn, from top to bottom.
  3927.   Stream pattern components are not restricted to quoted patterns (intended
  3928. to match stream elements), but can be also function calls (corresponding to
  3929. non-terminals, in the grammar terminology).  Functions appearing as stream
  3930. pattern components are intended to match substreams of the stream argument:
  3931. they are called on the actual stream argument, and they are followed by a
  3932. pattern which should match the result of this call.  For example, if we
  3933. define a parser recognizing a non empty sequence of characters `a`:
  3934.  
  3935. #let seq_a =
  3936. #    let rec seq = function
  3937. #        [< '`a`; seq l >] -> `a`::l
  3938. #      | [< >] -> []
  3939. #    in function [< '`a`; seq l >] -> `a`::l;;
  3940. seq_a : char stream -> char list = <fun>
  3941.  
  3942. we used the recursively defined function seq inside the stream pattern of
  3943. the first rule.  This definition should be read as:
  3944.  
  3945.  -  if the stream is not empty and if its first element matches `a`, apply
  3946.     seq to the rest of the stream, let l be the result of this call and
  3947.     return `a`::l,
  3948.  
  3949.  -  otherwise, fail (raise Parse_failure);
  3950.  
  3951. and seq should be read in the same way (except that, since it recognizes
  3952. possibly empty sequences of `a`, it never fails).
  3953.   Less operationally, we can read it as:  ``a non-empty sequence of `a`
  3954. starts with an `a`, and is followed by a possibly empty sequence of `a`.
  3955.   Another example is the recognition of a non-empty sequence of `a` followed
  3956. by a `b`, or a `b` alone:
  3957.  
  3958. #let seq_a_b = function
  3959. #  [< seq_a l; '`b` >] -> l@[`b`]
  3960. #| [< '`b` >] -> [`b`];;
  3961. seq_a_b : char stream -> char list = <fun>
  3962.  
  3963. Here, operationally, once an `a` has been recognized, the first matching
  3964. rule is chosen.  Any further mismatch (either from seq_a or from the last
  3965. `b`) will raise a Parse_error exception, and the whole parsing will fail.
  3966.  
  3967.  
  3968.                                      69
  3969.  
  3970.  
  3971.  
  3972. On the other hand, if the first character is not an `a`, seq_a will raise
  3973. Parse_failure, and the second rule ([< '`b` >] -> ...) will be tried.
  3974.   This behavior is typical of predictive parsers.  Predictive parsing is
  3975. recursive-descent parsing with one look-ahead token.  In other words, a
  3976. predictive parser is a set of (possibly mutually recursive) procedures,
  3977. which are selected according to the shape of (at most) the first token.
  3978.  
  3979. 10.2.2 Sequential binding in stream patterns
  3980.  
  3981. Bindings in stream patterns occur sequentially, in contrast with bindings in
  3982. regular patterns, which can be thought as occurring in parallel.  Stream
  3983. matching is guaranteed to be performed from left to right.  For example,
  3984. computing the sum of the elements of an integer stream could be defined as:
  3985.  
  3986. #let rec stream_sum n = function
  3987. #  [< '0; (stream_sum n) p >] -> p
  3988. #| [< 'x; (stream_sum (n+x)) p >] -> p
  3989. #| [< >] -> n;;
  3990. stream_sum : int -> int stream -> int = <fun>
  3991.  
  3992. #stream_sum 0 [< '0; '1; '2; '3; '4 >];;
  3993. - : int = 10
  3994.  
  3995. The stream_sum function uses its first argument as an accumulator holding
  3996. the sum computed so far.  The call (stream_sum (n+x)) uses x which was bound
  3997. in the stream pattern component occurring at the left of the call.
  3998.   Warning:  streams patterns are legal only in the function and match
  3999. constructs.  The let and other forms are restricted to usual patterns.
  4000. Furthermore, a stream pattern cannot appear inside another pattern.
  4001.  
  4002.  
  4003. 10.3 Parameterized parsers
  4004.  
  4005. Since a parser is a function like any other function, it can be
  4006. parameterized or be used as a parameter.  Parameters used only in the
  4007. right-hand side of stream-matching rules simulate inherited attributes of
  4008. attribute grammars.  Parameters used as parsers in stream patterns allow for
  4009. the implementation of higher-order parsers.  We will use the next example to
  4010. motivate the introduction of parameterized parsers.
  4011.  
  4012. 10.3.1 Example:  a parser for arithmetic expressions
  4013.  
  4014. Before building a parser for arithmetic expressions, we need a lexical
  4015. analyzer able to recognize arithmetic operations and integer constants.  Let
  4016. us first define a type for tokens:
  4017.  
  4018. #type token =
  4019. #  PLUS | MINUS | TIMES | DIV | LPAR | RPAR
  4020. #| INT of int;;
  4021. Type token defined.
  4022.  
  4023.  
  4024.  
  4025.                                      70
  4026.  
  4027.  
  4028.  
  4029. Skipping blank spaces is performed by the spaces function defined as:
  4030.  
  4031. #let rec spaces = function
  4032. #  [< '` `|`\t`|`\n`; spaces _ >] -> ()
  4033. #| [< >] -> ();;
  4034. spaces : char stream -> unit = <fun>
  4035.  
  4036. The conversion of a digit (character) into its integer value is done by:
  4037.  
  4038. #let int_of_digit = function
  4039. #  `0`..`9` as c -> (int_of_char c) - (int_of_char `0`)
  4040. #| _ -> raise (Failure "not a digit");;
  4041. int_of_digit : char -> int = <fun>
  4042.  
  4043. The ``as'' keyword allows for naming a pattern:  in this case, the variable
  4044. c will be bound to the actual digit matched by `0`..`9`.  Pattern built with
  4045. as are called alias patterns.
  4046.   For the recognition of integers, we already feel the need for a
  4047. parameterized parser.  Integer recognition is done by the integer analyzer
  4048. defined below.  It is parameterized by a numeric value representing the
  4049. value of the first digits of the number:
  4050.  
  4051. #let rec integer n = function
  4052. #  [< ' `0`..`9` as c; (integer (10*n + int_of_digit c)) r >] -> r
  4053. #| [< >] -> n;;
  4054. integer : int -> char stream -> int = <fun>
  4055.  
  4056. #integer 0 (stream_of_string "12345");;
  4057. - : int = 12345
  4058.  
  4059. We are now ready to write the lexical analyzer, taking a stream of
  4060. characters, and returning a stream of tokens.  Returning a token stream
  4061. which will be explored by the parser is a simple, reasonably efficient and
  4062. intuitive way of composing a lexical analyzer and a parser.
  4063.  
  4064. #let rec lexer s = match s with
  4065. #  [< '`(`; spaces _ >] -> [< 'LPAR; lexer s >]
  4066. #| [< '`)`; spaces _ >] -> [< 'RPAR; lexer s >]
  4067. #| [< '`+`; spaces _ >] -> [< 'PLUS; lexer s >]
  4068. #| [< '`-`; spaces _ >] -> [< 'MINUS; lexer s >]
  4069. #| [< '`*`; spaces _ >] -> [< 'TIMES; lexer s >]
  4070. #| [< '`/`; spaces _ >] -> [< 'DIV; lexer s >]
  4071. #| [< '`0`..`9` as c; (integer (int_of_digit c)) n; spaces _ >]
  4072. #                       -> [< 'INT n; lexer s >];;
  4073. lexer : char stream -> token stream = <fun>
  4074.  
  4075. We assume there is no leading space in the input.
  4076.   Now, let us examine the language that we want to recognize.  We shall have
  4077. integers, infix arithmetic operations and parenthesized expressions.  The
  4078. BNF form of the grammar is:
  4079.  
  4080.  
  4081.  
  4082.                                      71
  4083.  
  4084.  
  4085.  
  4086. Expr ::= Expr + Expr
  4087.        | Expr - Expr
  4088.        | Expr * Expr
  4089.        | Expr / Expr
  4090.        | ( Expr )
  4091.        | INT
  4092.  
  4093. The values computed by the parser will be abstract syntax trees (by contrast
  4094. with concrete syntax, which is the input string or stream).  Such trees
  4095. belong to the following type:
  4096.  
  4097. #type atree =
  4098. #  Int of int
  4099. #| Plus of atree * atree
  4100. #| Minus of atree * atree
  4101. #| Mult of atree * atree
  4102. #| Div of atree * atree;;
  4103. Type atree defined.
  4104.  
  4105. The Expr grammar is ambiguous.  To make it unambiguous, we will adopt the
  4106. usual precedences for arithmetic operators and assume that all operators
  4107. associate to the left.  Now, to use stream matching for parsing, we must
  4108. take into account the fact that matching rules are chosen according to the
  4109. behavior of the first component of each matching rule.  This is predictive
  4110. parsing, and, using well-known techniques, it is easy to rewrite the grammar
  4111. above in such a way that writing the corresponding predictive parser becomes
  4112. trivial.  These techniques are described in [2], and consist in adding a
  4113. non-terminal for each precedence level, and removing left-recursion.  We
  4114. obtain:
  4115.  
  4116. Expr ::= Mult
  4117.        | Mult + Expr
  4118.        | Mult - Expr
  4119.  
  4120. Mult ::= Atom
  4121.        | Atom * Mult
  4122.        | Atom / Mult
  4123.  
  4124. Atom ::= INT
  4125.        | ( Expr )
  4126.  
  4127. While removing left-recursion, we forgot about left associativity of
  4128. operators.  This is not a problem, as long as we build correct abstract
  4129. trees.
  4130.   Since stream matching bases its choices on the first component of stream
  4131. patterns, we cannot see the grammar above as a parser.  We need a further
  4132. transformation, factoring common prefixes of grammar rules (left-factor).
  4133. We obtain:
  4134.  
  4135. Expr ::= Mult RestExpr
  4136.  
  4137.  
  4138.  
  4139.                                      72
  4140.  
  4141.  
  4142.  
  4143.         RestExpr ::= + Mult RestExpr
  4144.                    | - Mult RestExpr
  4145.                    | (* nothing *)
  4146.  
  4147. Mult ::= Atom RestMult
  4148.  
  4149.         RestMult ::= * Atom RestMult
  4150.                    | / Atom RestMult
  4151.                    | (* nothing *)
  4152.  
  4153. Atom ::= INT
  4154.        | ( Expr )
  4155.  
  4156. Now, we can see this grammar as a parser (note that the order of rules
  4157. becomes important, and empty productions must appear last).  The shape of
  4158. the parser is:
  4159.  
  4160. let rec expr =
  4161.     let rec restexpr ? = function
  4162.         [< 'PLUS; mult ?; restexpr ? >] -> ?
  4163.       | [< 'MINUS; mult ?; restexpr ? >] -> ?
  4164.       | [< >] -> ?
  4165. in function [< mult e1; restexpr ? >] -> ?
  4166.  
  4167. and mult =
  4168.     let rec restmult ? = function
  4169.         [< 'TIMES; atom ?; restmult ? >] -> ?
  4170.       | [< 'DIV; atom ?; restmult ? >] -> ?
  4171.       | [< >] -> ?
  4172. in function [< atom e1; restmult ? >] -> ?
  4173.  
  4174. and atom = function
  4175.   [< 'INT n >] -> Int n
  4176. | [< 'LPAR; expr e; 'RPAR >] -> e
  4177.  
  4178. We used question marks where parameters, bindings and results still have to
  4179. appear.  Let us consider the expr function:  clearly, as soon as e1 is
  4180. recognized, we must be ready to build the leftmost subtree of the result.
  4181. This leftmost subtree is either restricted to e1 itself, in case restexpr
  4182. does not encounter any operator, or it is the tree representing the addition
  4183. (or subtraction) of e1 and the expression immediately following the additive
  4184. operator.  Therefore, restexpr must be called with e1 as an intermediate
  4185. result, and accumulate subtrees built from its intermediate result, the tree
  4186. constructor corresponding to the operator and the last expression
  4187. encountered.  The body of expr becomes:
  4188.  
  4189. let rec expr =
  4190.     let rec restexpr e1 = function
  4191.         [< 'PLUS; mult e2; restexpr (Plus (e1,e2)) e >] -> e
  4192.       | [< 'MINUS; mult e2; restexpr (Minus (e1,e2)) e >] -> e
  4193.       | [< >] -> e1
  4194.  
  4195.  
  4196.                                      73
  4197.  
  4198.  
  4199.  
  4200. in function [< mult e1; (restexpr e1) e2 >] -> e2
  4201.  
  4202. Now, expr recognizes a product e1 (by mult), and applies (restexpr e1) to
  4203. the rest of the stream.  According to the additive operator encountered (if
  4204. any), this function will apply mult which will return some e2.  Then the
  4205. process continues with Plus(e1,e2) as intermediate result.  In the end, a
  4206. correctly balanced tree will be produced (using the last rule of restexpr).
  4207.   With the same considerations on mult and restmult, we can complete the
  4208. parser, obtaining:
  4209.  
  4210. #let rec expr =
  4211. #    let rec restexpr e1 = function
  4212. #        [< 'PLUS; mult e2; (restexpr (Plus (e1,e2))) e >] -> e
  4213. #      | [< 'MINUS; mult e2; (restexpr (Minus (e1,e2))) e >] -> e
  4214. #      | [< >] -> e1
  4215. #in function [< mult e1; (restexpr e1) e2 >] -> e2
  4216. #
  4217. #and mult =
  4218. #    let rec restmult e1 = function
  4219. #        [< 'TIMES; atom e2; (restmult (Mult (e1,e2))) e >] -> e
  4220. #      | [< 'DIV; atom e2; (restmult (Div (e1,e2))) e >] -> e
  4221. #      | [< >] -> e1
  4222. #in function [< atom e1; (restmult e1) e2 >] -> e2
  4223. #
  4224. #and atom = function
  4225. #  [< 'INT n >] -> Int n
  4226. #| [< 'LPAR; expr e; 'RPAR >] -> e;;
  4227. expr : token stream -> atree = <fun>
  4228. mult : token stream -> atree = <fun>
  4229. atom : token stream -> atree = <fun>
  4230.  
  4231. And we can now try our parser:
  4232.  
  4233. #expr (lexer (stream_of_string "(1+2+3*4)-567"));;
  4234. - : atree = Minus (Plus (Plus (Int 1, Int 2), Mult (Int 3, Int 4)), Int 567)
  4235.  
  4236.  
  4237. 10.3.2 Parameters simulating inherited attributes
  4238.  
  4239. In the previous example, the parsers restexpr and restmult take an abstract
  4240. syntax tree e1 as argument and pass it down to the result through recursive
  4241. calls such as (restexpr (Plus(e1,e2))).  If we see such parsers as
  4242. non-terminals (RestExpr from the grammar above) this parameter acts as an
  4243. inherited attribute of the non-terminal.  Synthesized attributes are
  4244. simulated by the right hand sides of stream matching rules.
  4245.  
  4246. 10.3.3 Higher-order parsers
  4247.  
  4248. In the definition of expr, we may notice that the parsers expr and mult on
  4249. the one hand and restexpr and restmult on the other hand have exactly the
  4250. same structure.  To emphasize this similarity, if we define parsers for
  4251.  
  4252.  
  4253.                                      74
  4254.  
  4255.  
  4256.  
  4257. additive (resp.  multiplicative) operators by:
  4258.  
  4259. #let addop = function
  4260. #  [< 'PLUS >] -> (function (x,y) -> Plus(x,y))
  4261. #| [< 'MINUS >] -> (function (x,y) -> Minus(x,y))
  4262. #and multop = function
  4263. #  [< 'TIMES >] -> (function (x,y) -> Mult(x,y))
  4264. #| [< 'DIV >] -> (function (x,y) -> Div(x,y));;
  4265. addop : token stream -> atree * atree -> atree = <fun>
  4266. multop : token stream -> atree * atree -> atree = <fun>
  4267.  
  4268. we can rewrite the expr parser as:
  4269.  
  4270. #let rec expr =
  4271. #    let rec restexpr e1 = function
  4272. #        [< addop f; mult e2; (restexpr (f (e1,e2))) e >] -> e
  4273. #      | [< >] -> e1
  4274. #in function [< mult e1; (restexpr e1) e2 >] -> e2
  4275. #
  4276. #and mult =
  4277. #    let rec restmult e1 = function
  4278. #        [< multop f; atom e2; (restmult (f (e1,e2))) e >] -> e
  4279. #      | [< >] -> e1
  4280. #in function [< atom e1; (restmult e1) e2 >] -> e2
  4281. #
  4282. #and atom = function
  4283. #  [< 'INT n >] -> Int n
  4284. #| [< 'LPAR; expr e; 'RPAR >] -> e;;
  4285. expr : token stream -> atree = <fun>
  4286. mult : token stream -> atree = <fun>
  4287. atom : token stream -> atree = <fun>
  4288.  
  4289. Now, we take advantage of these similarities in order to define a general
  4290. parser for left-associative operators.  Its name is left_assoc and is
  4291. parameterized by a parser for operators and a parser for expressions:
  4292.  
  4293. #let rec left_assoc op term =
  4294. #    let rec rest e1 = function
  4295. #        [< op f; term e2; (rest (f (e1,e2))) e >] -> e
  4296. #      | [< >] -> e1
  4297. #    in function [< term e1; (rest e1) e2 >] -> e2;;
  4298. left_assoc :
  4299.  ('a stream -> 'b * 'b -> 'b) -> ('a stream -> 'b) -> 'a stream -
  4300. > 'b = <fun>
  4301.  
  4302. Now, we can redefine expr as:
  4303.  
  4304. #let rec expr str = left_assoc addop mult str
  4305. #and mult str = left_assoc multop atom str
  4306. #and atom = function
  4307. #  [< 'INT n >] -> Int n
  4308.  
  4309.  
  4310.                                      75
  4311.  
  4312.  
  4313.  
  4314. #| [< 'LPAR; expr e; 'RPAR >] -> e;;
  4315. expr : token stream -> atree = <fun>
  4316. mult : token stream -> atree = <fun>
  4317. atom : token stream -> atree = <fun>
  4318.  
  4319. And we can now try our definitive parser:
  4320.  
  4321. #expr (lexer (stream_of_string "(1+2+3*4)-567"));;
  4322. - : atree = Minus (Plus (Plus (Int 1, Int 2), Mult (Int 3, Int 4)), Int 567)
  4323.  
  4324. Parameterized parsers are useful for defining general parsers such as
  4325. left_assoc that can be used with different instances.  Another example of a
  4326. useful general parser is the star parser defined as:
  4327.  
  4328. #let rec star p = function
  4329. #  [< p x; (star p) l >] -> x::l
  4330. #| [< >] -> [];;
  4331. star : ('a stream -> 'b) -> 'a stream -> 'b list = <fun>
  4332.  
  4333. The star parser iterates zero or more times its argument p and returns the
  4334. list of results.  We still have to be careful in using these general parsers
  4335. because of the predictive nature of parsing.  For example, star p will never
  4336. successfully terminate if p has a rule for the empty stream pattern:  this
  4337. rule will make the second rule of star useless!
  4338.  
  4339. 10.3.4 Example:  parsing a non context-free language
  4340.  
  4341. As an example of parsing with parameterized parsers, we shall build a parser
  4342. for the language {wCw | w#(A|B)*}, which is known to be non context-free.
  4343.   First, let us define a type for this alphabet:
  4344.  
  4345. #type token = A | B | C;;
  4346. Type token defined.
  4347.  
  4348. Given an input of the form wCw, the idea for a parser recognizing it is:
  4349.  
  4350.  -  first, to recognize the sequence w with a parser wd (for word
  4351.     definition) returning information in order to build a parser recognizing
  4352.     only w;
  4353.  
  4354.  -  then to recognize C;
  4355.  
  4356.  -  and to use the parser built at the first step to recognize the sequence
  4357.     w.
  4358.  
  4359. The definition of wd is as follows:
  4360.  
  4361. #let rec wd = function
  4362. #  [< 'A; wd l >] -> (function [< 'A >] -> "a")::l
  4363. #| [< 'B; wd l >] -> (function [< 'B >] -> "b")::l
  4364. #| [< >] -> [];;
  4365.  
  4366.  
  4367.                                      76
  4368.  
  4369.  
  4370.  
  4371. wd : token stream -> (token stream -> string) list = <fun>
  4372.  
  4373. The wu function (for word usage) builds a parser sequencing a list of
  4374. parsers:
  4375.  
  4376. #let rec wu = function
  4377. #  p::pl -> (function [< p x; (wu pl) l >] -> x^l)
  4378. #| [] -> (function [< >] -> "");;
  4379. wu : ('a stream -> string) list -> 'a stream -> string = <fun>
  4380.  
  4381. The wu function builds, from a list of parsers pi, for i=1..n, a single
  4382. parser
  4383.  
  4384.                function [<p1 x1;.. .;pn xn>] -> [x1;.. .;xn]
  4385.  
  4386. which is the sequencing of parsers pi.  The main parser w is:
  4387.  
  4388. #let w = function [< wd l; 'C; (wu l) r >] -> r;;
  4389. w : token stream -> string = <fun>
  4390.  
  4391. #w [< 'A; 'B; 'B; 'C; 'A; 'B; 'B >];;
  4392. - : string = "abb"
  4393.  
  4394. #w [< 'C >];;
  4395. - : string = ""
  4396.  
  4397.   In the previous parser, we used an intermediate list of parsers in order
  4398. to build the second parser.  We can redefine wd without using such a list:
  4399.  
  4400. #let w =
  4401. #    let rec wd wr = function
  4402. #        [< 'A; (wd (function [< wr r; 'A >] -> r^"a")) p >] -> p
  4403. #      | [< 'B; (wd (function [< wr r; 'B >] -> r^"b")) p >] -> p
  4404. #      | [< >] -> wr
  4405. #    in function [< (wd (function [< >] -> "")) p; 'C; p str >] -> str;;
  4406. w : token stream -> string = <fun>
  4407.  
  4408. #w [< 'A; 'B; 'B; 'C; 'A; 'B; 'B >];;
  4409. - : string = "abb"
  4410.  
  4411. #w [< 'C >];;
  4412. - : string = ""
  4413.  
  4414. Here, wd is made local to w, and takes as parameter wr (for word recognizer)
  4415. whose initial value is the parser with an empty stream pattern.  This
  4416. parameter accumulates intermediate results, and is delivered at the end of
  4417. parsing the initial sequence w.  After checking for the presence of C, it is
  4418. used to parse the second sequence w.
  4419.  
  4420.  
  4421.  
  4422.  
  4423.  
  4424.                                      77
  4425.  
  4426.  
  4427.  
  4428. 10.4 Further reading
  4429.  
  4430. A summary of the constructs over streams and of primitives over streams is
  4431. given in [20].
  4432.   An alternative to parsing with streams and stream matching are the camllex
  4433. and camlyacc programs.
  4434.   A detailed presentation of streams and stream matching following
  4435. ``predictive parsing'' semantics can be found in [25], where alternative
  4436. semantics are given with some possible implementations.
  4437.  
  4438.  
  4439. Exercises
  4440.  
  4441. Exercise 10.1 Define a parser for the language of prefix arithmetic
  4442. expressions generated by the grammar:
  4443.  
  4444. Expr ::= INT
  4445.        | + Expr Expr
  4446.        | - Expr Expr
  4447.        | * Expr Expr
  4448.        | / Expr Expr
  4449.  
  4450. Use the lexical analyzer for arithmetic expressions given above.  The result
  4451. of the parser must be the integer resulting from the evaluation of the
  4452. arithmetic expression, i.e.  its type must be:
  4453.  
  4454.                                 token -> int
  4455.  
  4456. Exercise 10.2 Enrich the type token above with a constructor IDENT of
  4457. string for identifiers, and enrich the lexical analyzer for it to recognize
  4458. identifiers built from alphabetic letters (upper or lowercase).  Length of
  4459. identifiers may be limited.
  4460.  
  4461.  
  4462.  
  4463.  
  4464.  
  4465.  
  4466.  
  4467.  
  4468.  
  4469.  
  4470.  
  4471.  
  4472.  
  4473.  
  4474.  
  4475.  
  4476.  
  4477.  
  4478.  
  4479.  
  4480.  
  4481.                                      78
  4482.  
  4483.  
  4484.  
  4485.  
  4486.  
  4487.  
  4488.  
  4489.  
  4490.  
  4491. Chapter 11
  4492.  
  4493.  
  4494.  
  4495. Standalone programs and separate compilation
  4496.  
  4497.  
  4498.  
  4499. So far, we have used Caml Light in an interactive way.  It is also possible
  4500. to program in Caml Light in a batch-oriented way:  writing source code in a
  4501. file, having it compiled into an executable program, and executing the
  4502. program outside of the Caml Light environment.  Interactive use is great for
  4503. learning the language and quickly testing new functions.  Batch use is more
  4504. convenient to develop larger programs, that should be usable without
  4505. knowledge of Caml Light.
  4506.   Note for Macintosh users:  batch compilation is not available in the
  4507. standalone Caml Light application.  It requires the MPW environment (see the
  4508. Caml Light manual).
  4509.  
  4510.  
  4511. 11.1 Standalone programs
  4512.  
  4513. Standalone programs are composed of a sequence of phrases, contained in one
  4514. or several text files.  Phrases are the same as at toplevel:  expressions,
  4515. value declarations, type declarations, exception declarations, and
  4516. directives.  When executing the stand-alone program produced by the
  4517. compiler, all phrases are executed in order.  The values of expressions and
  4518. declared global variables are not printed, however.  A stand-alone program
  4519. has to perform input and output explicitly.
  4520.   Here is a sample program, that prints the number of characters and the
  4521. number of lines of its standard input, like the wc Unix utility.
  4522.  
  4523. let chars = ref 0;;
  4524. let lines = ref 0;;
  4525. try
  4526.   while true do
  4527.     let c = input_char std_in in
  4528.       chars := !chars + 1;
  4529.       if c = `\n` then lines := !lines + 1 else ()
  4530.   done
  4531. with End_of_file ->
  4532.   print_int !chars; print_string " characters, ";
  4533.   print_int !lines; print_string " lines.\n";
  4534.   exit 0
  4535. ;;
  4536.  
  4537.  
  4538.                                      79
  4539.  
  4540.  
  4541.  
  4542.   The input_char function reads the next character from an input channel
  4543. (here, std_in, the channel connected to standard input).  It raises
  4544. exception End_of_file when reaching the end of the file.  The exit function
  4545. aborts the process.  Its argument is the exit status of the process.
  4546. Calling exit is absolutely necessary to ensure proper flushing of the output
  4547. channels.
  4548.   Assume this program is in file count.ml.  To compile it, simply run the
  4549. camlc command from the command interpreter:
  4550.  
  4551. camlc -o count count.ml
  4552.  
  4553. The compiler produces an executable file count.  You can now run count with
  4554. the help of the "camlrun" command:
  4555.  
  4556. camlrun count < count.ml
  4557.  
  4558. This should display something like:
  4559.  
  4560. 306 characters, 13 lines.
  4561.  
  4562. Under Unix, the count file can actually be executed directly, just like any
  4563. other Unix command, as in:
  4564.  
  4565. ./count < count.ml
  4566.  
  4567. This also works under MS-DOS, provided the executable file is given
  4568. extension .exe.  That is, if we compile count.ml as follows:
  4569.  
  4570. camlc -o count.exe count.ml
  4571.  
  4572. we can run count.exe directly, as in:
  4573.  
  4574. count.exe < count.ml
  4575.  
  4576. See the reference manual for more information on camlc.
  4577.  
  4578.  
  4579. 11.2 Programs in several files
  4580.  
  4581. It is possible to split one program into several source files, separately
  4582. compiled.  This way, local changes do not imply a full recompilation of the
  4583. program.  Let us illustrate that on the previous example.  We split it in
  4584. two modules:  one that implements integer counters; another that performs
  4585. the actual counting.  Here is the first one, counter.ml:
  4586.  
  4587. (* counter.ml *)
  4588. type counter = { mutable val: int };;
  4589. let new init = { val = init };;
  4590. let incr c = c.val <- c.val + 1;;
  4591. let read c = c.val;;
  4592.  
  4593.  
  4594.  
  4595.                                      80
  4596.  
  4597.  
  4598.  
  4599. Here is the source for the main program, in file main.ml.
  4600.  
  4601. (* main.ml *)
  4602. let chars = counter__new 0;;
  4603. let lines = counter__new 0;;
  4604. try
  4605.   while true do
  4606.     let c = input_char std_in in
  4607.       counter__incr chars;
  4608.       if c = `\n` then counter__incr lines else ()
  4609.   done
  4610. with End_of_file ->
  4611.   print_int (counter__read chars); print_string " characters, ";
  4612.   print_int (counter__read lines); print_string " lines.\n";
  4613.   exit 0
  4614. ;;
  4615.  
  4616. Notice that references to identifiers defined in module counter.ml are
  4617. prefixed with the name of the module, counter, and by __ (the ``long dash''
  4618. symbol:  two underscore characters).  If we had simply entered new 0, for
  4619. instance, the compiler would have assumed new is an identifier declared in
  4620. the current module, and issued an ``undefined identifier'' error.
  4621.   Compiling this program requires two compilation steps, plus one final
  4622. linking step.
  4623.  
  4624. camlc -c counter.ml
  4625. camlc -c main.ml
  4626. camlc -o main counter.zo main.zo
  4627.  
  4628. Running the program is done as before:
  4629.  
  4630. camlrun main < counter.ml
  4631.  
  4632. The -c option to camlc means ``compile only''; that is, the compiler should
  4633. not attempt to produce a stand-alone executable program from the given file,
  4634. but simply an object code file (files counter.zo, main.zo).  The final
  4635. linking phases takes the two .zo files and produces the executable main.
  4636. Object files must be linked in the right order:  for each global identifier,
  4637. the module defining it must come before the modules that use it.
  4638.  
  4639.   Prefixing all external identifiers by the name of their defining module is
  4640. sometimes tedious.  Therefore, the Caml Light compiler provides a mechanism
  4641. to omit the module__ part in external identifiers.  The system maintains a
  4642. list of ``default'' modules, called the currently opened modules, and
  4643. whenever it encounters an identifier without the module__ part, it searches
  4644. through the opened modules, to find one that defines this identifier.
  4645. Searched modules always include the module being compiled (searched first),
  4646. and some library modules of general use.  In addition, two directives are
  4647. provided to add and to remove modules from the list of opened modules:
  4648.  
  4649.  -  #open "module";; to add module in front of the list;
  4650.  
  4651.  
  4652.                                      81
  4653.  
  4654.  
  4655.  
  4656.  -  #close "module";; to remove module from the list.
  4657.  
  4658. For instance, we can rewrite the main.ml file above as:
  4659.  
  4660. #open "counter";;
  4661. let chars = new 0;;
  4662. let lines = new 0;;
  4663. try
  4664.   while true do
  4665.     let c = input_char std_in in
  4666.       incr chars;
  4667.       if c = `\n` then incr lines
  4668.   done
  4669. with End_of_file ->
  4670.   print_int (read chars);
  4671.   print_string " characters, ";
  4672.   print_int (read lines);
  4673.   print_string " lines.\n";
  4674.   exit 0
  4675. ;;
  4676.  
  4677. After the #open "counter" directive, the identifier new automatically
  4678. resolves to counters__new.
  4679.   If two modules, say mod1 and mod2, define both a global value f, then f in
  4680. a client module client resolves to mod1__f if mod1 is opened but not mod2,
  4681. or if mod1 has been opened more recently than mod2.  Otherwise, it resolves
  4682. to mod2__f.  For instance, the two system modules int and float both define
  4683. the infix identifier +.  Both modules int and float are opened by default,
  4684. but int comes first.  Hence, x + y is understood as the integer addition,
  4685. since + is resolved to int__+.  But after the directive #open "float";;,
  4686. module float comes first, and the identifier + is resolved to float__+.
  4687.  
  4688.  
  4689. 11.3 Abstraction
  4690.  
  4691. Some globals defined in a module are not intended to be used outside of this
  4692. module.  Then, it is good programming style not to export them outside of
  4693. the module, so that the compiler can check they are not used in another
  4694. module.  Also, one may wish to export a data type abstractly, that is,
  4695. without publicizing the structure of the type.  This ensures that other
  4696. modules cannot build or inspect objects of that type without going through
  4697. one of the functions on that type exported in the defining module.  This
  4698. helps in writing clean, well-structured programs.
  4699.   The way to do that in Caml Light is to write an explicit interface, or
  4700. output signature, specifying those identifiers that are visible from the
  4701. outside.  All other identifiers will remain local to the module.  For global
  4702. values, their types must be given by hand.  The interface is contained in a
  4703. file whose name is the module name, with extension .mli.
  4704.   Here is for instance an interface for the counter module, that abstracts
  4705. the type counter:
  4706.  
  4707.  
  4708.  
  4709.                                      82
  4710.  
  4711.  
  4712.  
  4713. (* counter.mli *)
  4714. type counter;;        (* an abstract type *)
  4715. value new : int -> counter
  4716.   and incr : counter -> unit
  4717.   and read : counter -> int;;
  4718.  
  4719.   Interfaces must be compiled separately.  However, once the interface for
  4720. module A has been compiled, any module B that uses A can be immediately
  4721. compiled, even if the implementation of A is not yet compiled or even not
  4722. yet written.  Consider:
  4723.  
  4724. camlc -c counter.mli
  4725. camlc -c main.ml
  4726. camlc -c counter.ml
  4727. camlc -o main counter.zo main.zo
  4728.  
  4729. The implementation main.ml could be compiled before counter.ml.  The only
  4730. requirement for compiling main.ml is the existence of counter.zi, the
  4731. compiled interface of the counter module.
  4732.  
  4733.  
  4734. Exercises
  4735.  
  4736. Exercise 11.1 Complete the count command:  it should be able to operate on
  4737. several files, given on the command line.  Hint:  sys__command_line is an
  4738. array of strings, containing the command-line arguments to the process.
  4739.  
  4740.  
  4741.  
  4742.  
  4743.  
  4744.  
  4745.  
  4746.  
  4747.  
  4748.  
  4749.  
  4750.  
  4751.  
  4752.  
  4753.  
  4754.  
  4755.  
  4756.  
  4757.  
  4758.  
  4759.  
  4760.  
  4761.  
  4762.  
  4763.  
  4764.  
  4765.  
  4766.                                      83
  4767.  
  4768.  
  4769.  
  4770.  
  4771.  
  4772.  
  4773.  
  4774.  
  4775.  
  4776.  
  4777.  
  4778.  
  4779.  
  4780.  
  4781.  
  4782.  
  4783.  
  4784.  
  4785.  
  4786.  
  4787.                                   Part III
  4788.  
  4789.  
  4790.  
  4791.                              A complete example
  4792.  
  4793.  
  4794.  
  4795.  
  4796.  
  4797.  
  4798.  
  4799.  
  4800.  
  4801.  
  4802.  
  4803.  
  4804.  
  4805.  
  4806.  
  4807.  
  4808.  
  4809.  
  4810.  
  4811.  
  4812.  
  4813.  
  4814.  
  4815.  
  4816.  
  4817.  
  4818.  
  4819.  
  4820.  
  4821.  
  4822.  
  4823.                                      84
  4824.  
  4825.  
  4826.  
  4827.  
  4828.  
  4829.  
  4830.  
  4831.  
  4832.  
  4833. Chapter 12
  4834.  
  4835.  
  4836.  
  4837. ASL: A Small Language
  4838.  
  4839.  
  4840.  
  4841. We present in this chapter a simple language:  ASL (A Small Language).  This
  4842. language is basically the l-calculus (the purely functional kernel of Caml)
  4843. enriched with a conditional construct.  The conditional must be a special
  4844. construct, because our language will be submitted to call-by-value:  thus,
  4845. the conditional cannot be a function.
  4846.   ASL programs are built up from numbers, variables, functional expressions
  4847. (l-abstractions), applications and conditionals.  An ASL program consists of
  4848. a global declaration of an identifier getting bound to the value of an
  4849. expression.  The primitive functions that are available are equality between
  4850. numbers and arithmetic binary operations.  The concrete syntax of ASL
  4851. expressions can be described (ambiguously) as:
  4852.  
  4853.     Expr ::= INT
  4854.            | IDENT
  4855.            | "if" Expr "then" Expr "else" Expr "fi"
  4856.            | "(" Expr ")"
  4857.            | "\" IDENT "." Expr
  4858.  
  4859.     and the syntax of declarations is given as:
  4860.  
  4861.  
  4862.     Decl ::= "let" IDENT "be" Expr ";"
  4863.            | Expr ";"
  4864.  
  4865.  
  4866. Arithmetic binary operations will be written in prefix position and will
  4867. belong to the class IDENT. The \ symbol will play the role of the Caml
  4868. keyword function.
  4869.   We start by defining the abstract syntax of ASL expressions and of ASL
  4870. toplevel phrases.  Then we define a parser in order to produce abstract
  4871. syntax trees from the concrete syntax of ASL programs.
  4872.  
  4873.  
  4874. 12.1 ASL abstract syntax trees
  4875.  
  4876. We encode variable names by numbers.  These numbers represent the binding
  4877. depth of variables.  For instance, the function of x returning x (the ASL
  4878.  
  4879.  
  4880.                                      85
  4881.  
  4882.  
  4883.  
  4884. identity function) will be represented as:
  4885.  
  4886. Abs("x", Var 1)
  4887.  
  4888. And the ASL application function which would be written in Caml:
  4889.  
  4890. (function f -> (function x -> f(x)))
  4891.  
  4892. would be represented as:
  4893.  
  4894. Abs("f", Abs("x", App(Var 2, Var 1)))
  4895.  
  4896. and should be viewed as the tree:
  4897.                                 Abs
  4898.                             "f" / \ Abs
  4899.                                 "x" / \ App
  4900.                                    Var 2/\ Var 1
  4901.  
  4902. Var n should be read as ``an occurrence of the variable bound by the nth
  4903. abstraction node encountered when going toward the root of the abstract
  4904. syntax tree''.  In our example, when going from Var 2 to the root, the 2nd
  4905. abstraction node we encounter introduces the "f" variable.
  4906.   The numbers encoding variables in abstract syntax trees of functional
  4907. expressions are called ``De Bruijn(1) numbers''.  The characters that we
  4908. attach to abstraction nodes simply serve as documentation:  they will not be
  4909. used by any of the semantic analyses that we will perform on the trees.  The
  4910. type of ASL abstract syntax trees is defined by:
  4911.  
  4912. #type asl = Const of int
  4913. #         | Var of int
  4914. #         | Cond of asl * asl * asl
  4915. #         | App of asl * asl
  4916. #         | Abs of string * asl
  4917. #
  4918. #and top_asl = Decl of string * asl;;
  4919. Type asl defined.
  4920. Type top_asl defined.
  4921.  
  4922.  
  4923.  
  4924. 12.2 Parsing ASL programs
  4925.  
  4926. Now we come to the problem of defining a concrete syntax for ASL programs
  4927. and declarations.
  4928.  
  4929. ------------------------------
  4930.  1. They have been proposed by N.G. De Bruijn in [10] in order to facilitate
  4931. the mechanical treatment of l-calculus terms.
  4932.  
  4933.  
  4934.  
  4935.                                      86
  4936.  
  4937.  
  4938.  
  4939.   The choice of the concrete aspect of the programs is simply a matter of
  4940. taste.  The one we choose here is close to the syntax of l-calculus (except
  4941. that we will use the backslash character because there is no ``l'' on our
  4942. keyboards).  We will use the curried versions of equality and arithmetic
  4943. functions.  We will also use a prefix notation (a la Lisp) for their
  4944. application.  We will write ``+ (+ 1 2) 3'' instead of ``(1+2)+3''.  The
  4945. ``if e1 then e2 else e3'' construct will be written ``if e1 then e2 else e3
  4946. fi'', and will return the then part when e1 is different from 0 (0 acts
  4947. thus as falsity in ASL conditionals).
  4948.  
  4949. 12.2.1 Lexical analysis
  4950.  
  4951. The concrete aspect of ASL programs will be either declarations of the form:
  4952.  
  4953.     let identifier be expression;
  4954.  
  4955. or:
  4956.  
  4957.     expression;
  4958.  
  4959. which will be understood as:
  4960.  
  4961.     let it be expression;
  4962.  
  4963. The tokens produced by the lexical analyzer will represent the keywords let,
  4964. be, if and else, the \ binder, the dot, parentheses, integers, identifiers,
  4965. arithmetic operations and terminating semicolons.  We reuse here most of the
  4966. code that we developed in chapter 10 or in the answers to its exercises.
  4967.   Skipping blank spaces:
  4968.  
  4969. #let rec spaces = function
  4970. #  [< '` `|`\t`|`\n`; spaces _ >] -> ()
  4971. #| [< >] -> ();;
  4972. spaces : char stream -> unit = <fun>
  4973.  
  4974. The type of tokens is given by:
  4975.  
  4976. #type token = LET | BE | LAMBDA | DOT | LPAR | RPAR
  4977. #           | IF | THEN | ELSE | FI | SEMIC
  4978. #           | INT of int | IDENT of string;;
  4979. Type token defined.
  4980.  
  4981. Integers:
  4982.  
  4983. #let int_of_digit = function
  4984. #  `0`..`9` as c -> (int_of_char c) - (int_of_char `0`)
  4985. #| _ -> raise (Failure "not a digit");;
  4986. int_of_digit : char -> int = <fun>
  4987.  
  4988. #let rec integer n = function
  4989.  
  4990.  
  4991.                                      87
  4992.  
  4993.  
  4994.  
  4995. #  [< ' `0`..`9` as c; (integer (10*n + int_of_digit c)) r >] -> r
  4996. #| [< >] -> INT n;;
  4997. integer : int -> char stream -> token = <fun>
  4998.  
  4999. We restrict ASL identifiers to be composed of lowercase letters, the eight
  5000. first being significative.  An explanation about the ident function can be
  5001. found in the chapter dedicated to the answers to exercises (chapter 17).
  5002. The function given here is slightly different and tests its result in order
  5003. to see wether it is a keyword (let, be, ...) or not:
  5004.  
  5005. #let ident_buf = make_string 8 ` `;;
  5006. ident_buf : string = "        "
  5007.  
  5008. #let rec ident len = function
  5009. #  [< ' `a`..`z` as c;
  5010. #     (if len >= 8 then ident len
  5011. #      else begin
  5012. #            set_nth_char ident_buf len c;
  5013. #            ident (succ len)
  5014. #           end) s >] -> s
  5015. #| [< >] -> (match sub_string ident_buf 0 len
  5016. #            with "let" -> LET
  5017. #               | "be" -> BE
  5018. #               | "if" -> IF
  5019. #               | "then" -> THEN
  5020. #               | "else" -> ELSE
  5021. #               | "fi" -> FI
  5022. #               | s -> IDENT s);;
  5023. ident : int -> char stream -> token = <fun>
  5024.  
  5025. A reasonable lexical analyzer would use a hash table to recognize keywords
  5026. faster.
  5027.   Primitive operations are recognized by the following function, which also
  5028. detects illegal operators and ends of input:
  5029.  
  5030. #let oper = function
  5031. #  [< '`+`|`-`|`*`|`/`|`=` as c >] -> IDENT(make_string 1 c)
  5032. #| [< 'c >] -> prerr_string "Illegal character: ";
  5033. #              prerr_endline (char_for_read c);
  5034. #              raise (Failure "ASL parsing")
  5035. #| [< >] -> prerr_endline "Unexpected end of input";
  5036. #           raise (Failure "ASL parsing");;
  5037. oper : char stream -> token = <fun>
  5038.  
  5039. The lexical analyzer has the same structure as the one given in chapter 10
  5040. except that leading blanks are skipped.
  5041.  
  5042. #let rec lexer str = spaces str;
  5043. #match str with
  5044. #  [< '`(`; spaces _ >]  -> [< 'LPAR; lexer str >]
  5045. #| [< '`)`; spaces _ >]  -> [< 'RPAR; lexer str >]
  5046.  
  5047.  
  5048.                                      88
  5049.  
  5050.  
  5051.  
  5052. #| [< '`\\`; spaces _ >] -> [< 'LAMBDA; lexer str >]
  5053. #| [< '`.`; spaces _ >]  -> [< 'DOT; lexer str >]
  5054. #| [< '`;`; spaces _ >]  -> [< 'SEMIC; lexer str >]
  5055. #| [< '`0`..`9` as c;
  5056. #     (integer (int_of_digit c)) tok;
  5057. #      spaces _ >]       -> [< 'tok; lexer str >]
  5058. #| [< '`a`..`z` as c;
  5059. #     (set_nth_char ident_buf 0 c; ident 1) tok;
  5060. #     spaces _ >]        -> [< 'tok; lexer str >]
  5061. #| [< oper tok; spaces _ >] -> [< 'tok; lexer str >]
  5062. #;;
  5063. lexer : char stream -> token stream = <fun>
  5064.  
  5065. The lexical analyzer returns a stream of tokens that the parser will receive
  5066. as argument.
  5067.  
  5068. 12.2.2 Parsing
  5069.  
  5070. The final output of our parser will be abstract syntax trees of type asl or
  5071. top_asl.  This implies that we will detect unbound identifiers at
  5072. parse-time.  In this case, we will raise the Unbound exception defined as:
  5073.  
  5074. #exception Unbound of string;;
  5075. Exception Unbound defined.
  5076.  
  5077. We also need a function which will compute the binding depths of variables.
  5078. That function simply looks for the position of the first occurrence of a
  5079. variable name in a list.  It will raise Unbound if there is no such
  5080. occurrence.
  5081.  
  5082. #let binding_depth s rho =
  5083. # let rec bind n = function
  5084. #     []  -> raise (Unbound s)
  5085. #  | t::l -> if s = t then Var n else bind (n+1) l
  5086. #  in bind 1 rho
  5087. #;;
  5088. binding_depth : string -> string list -> asl = <fun>
  5089.  
  5090. We also need a global environment, containing names of already bound
  5091. identifiers.  The global environment contains predefined names for the
  5092. equality and arithmetic functions.  We represent the global environment as a
  5093. reference since each ASL declaration will augment it with a new name.
  5094.  
  5095. #let init_env =  ["+";"-";"*";"/";"="];;
  5096. init_env : string list = ["+"; "-"; "*"; "/"; "="]
  5097.  
  5098. #let global_env = ref init_env;;
  5099. global_env : string list ref = ref ["+"; "-"; "*"; "/"; "="]
  5100.  
  5101. We now give a parsing function for ASL programs.  Blanks at the beginning of
  5102. the string are skipped.
  5103.  
  5104.  
  5105.                                      89
  5106.  
  5107.  
  5108.  
  5109. #let rec top = function
  5110. #    [< 'LET; 'IDENT id; 'BE; expression e; 'SEMIC >] -> Decl(id,e)
  5111. #  | [< expression e; 'SEMIC >] -> Decl("it",e)
  5112. #
  5113. #and expression = function
  5114. #    [< (expr !global_env) e >] -> e
  5115. #
  5116. #and expr rho =
  5117. #  let rec rest e1 = function
  5118. #          [< (atom rho) e2; (rest (App(e1,e2))) e >] -> e
  5119. #        | [< >] -> e1
  5120. #  in function
  5121. #       [< 'LAMBDA; 'IDENT id; 'DOT; (expr (id::rho)) e >] -> Abs(id,e)
  5122. #     | [< (atom rho) e1; (rest e1) e2 >] -> e2
  5123. #
  5124. #and atom rho = function
  5125. #    [< 'IDENT id >] ->
  5126. #        (try binding_depth id rho with Unbound s ->
  5127. #              print_string "Unbound ASL identifier: ";
  5128. #              print_string s; print_newline();
  5129. #              raise (Failure "ASL parsing"))
  5130. #  | [< 'INT n >] -> Const n
  5131. #  | [< 'IF; (expr rho) e1; 'THEN; (expr rho) e2;
  5132. #       'ELSE; (expr rho) e3; 'FI >] -> Cond(e1,e2,e3)
  5133. #  | [< 'LPAR; (expr rho) e; 'RPAR >] -> e;;
  5134. top : token stream -> top_asl = <fun>
  5135. expression : token stream -> asl = <fun>
  5136. expr : string list -> token stream -> asl = <fun>
  5137. atom : string list -> token stream -> asl = <fun>
  5138.  
  5139. The complete parser that we will use reads a string, converts it into a
  5140. stream, and produces the token stream that is parsed:
  5141.  
  5142. #let parse_top s = top(lexer(stream_of_string s));;
  5143. parse_top : string -> top_asl = <fun>
  5144.  
  5145. Let us try our grammar (we do not augment the global environment at each
  5146. declaration:  this will be performed after the semantic treatment of ASL
  5147. programs).  We need to write double \ inside strings, since \ is the string
  5148. escape character.
  5149.  
  5150. #parse_top "let f be \\x.x;";;
  5151. - : top_asl = Decl ("f", Abs ("x", Var 1))
  5152.  
  5153. #parse_top "let x be + 1 ((\\x.x) 2);";;
  5154. - : top_asl =
  5155.  Decl ("x", App (App (Var 1, Const 1), App (Abs ("x", Var 1), Const 2)))
  5156.  
  5157. Unbound identifiers and undefined operators are correctly detected:
  5158.  
  5159. #parse_top "let y be g 3;";;
  5160.  
  5161.  
  5162.                                      90
  5163.  
  5164.  
  5165.  
  5166. Unbound ASL identifier: g
  5167. Uncaught exception: Failure "ASL parsing"
  5168.  
  5169. #parse_top "f (if 0 then + else - fi) 2 3;";;
  5170. Unbound ASL identifier: f
  5171. Uncaught exception: Failure "ASL parsing"
  5172.  
  5173. #parse_top "^ x y;";;
  5174. Illegal character: ^
  5175. Uncaught exception: Failure "ASL parsing"
  5176.  
  5177.  
  5178.  
  5179.  
  5180.  
  5181.  
  5182.  
  5183.  
  5184.  
  5185.  
  5186.  
  5187.  
  5188.  
  5189.  
  5190.  
  5191.  
  5192.  
  5193.  
  5194.  
  5195.  
  5196.  
  5197.  
  5198.  
  5199.  
  5200.  
  5201.  
  5202.  
  5203.  
  5204.  
  5205.  
  5206.  
  5207.  
  5208.  
  5209.  
  5210.  
  5211.  
  5212.  
  5213.  
  5214.  
  5215.  
  5216.  
  5217.  
  5218.  
  5219.                                      91
  5220.  
  5221.  
  5222.  
  5223.  
  5224.  
  5225.  
  5226.  
  5227.  
  5228.  
  5229. Chapter 13
  5230.  
  5231.  
  5232.  
  5233. Untyped semantics of ASL programs
  5234.  
  5235.  
  5236.  
  5237. In this section, we give a semantic treatment of ASL programs.  We will use
  5238. dynamic typechecking, i.e.  we will test the type correctness of programs
  5239. during their interpretation.
  5240.  
  5241.  
  5242. 13.1 Semantic values
  5243.  
  5244. We need a type for ASL semantic values (representing results of
  5245. computations).  A semantic value will be either an integer, or a Caml
  5246. functional value from ASL values to ASL values.
  5247.  
  5248. #type semval = Constval of int
  5249. #            | Funval of (semval -> semval);;
  5250. Type semval defined.
  5251.  
  5252. We now define two exceptions.  The first one will be used when we encounter
  5253. an ill-typed program and will represent run-time type errors.  The other one
  5254. is helpful for debugging:  it will be raised when our interpreter (semantic
  5255. function) goes into an illegal situation.
  5256.   The following two exceptions will be raised in case of run-time ASL type
  5257. error, and in case of bug of our semantic treatment:
  5258.  
  5259. #exception Illtyped;;
  5260. Exception Illtyped defined.
  5261.  
  5262. #exception SemantBug of string;;
  5263. Exception SemantBug defined.
  5264.  
  5265. We must give a semantic value to our basic functions (equality and
  5266. arithmetic operations).  The next function transforms a Caml function into
  5267. an ASL value.
  5268.  
  5269. #let init_semantics caml_fun =
  5270. #    Funval
  5271. #      (function Constval n ->
  5272. #         Funval(function Constval m -> Constval(caml_fun n m)
  5273. #                        | _ -> raise Illtyped)
  5274.  
  5275.  
  5276.                                      92
  5277.  
  5278.  
  5279.  
  5280. #              | _ -> raise Illtyped);;
  5281. init_semantics : (int -> int -> int) -> semval = <fun>
  5282.  
  5283.   Now, associate a Caml Light function to each ASL predefined function:
  5284.  
  5285. #let caml_function = function
  5286. #    "+" -> prefix +
  5287. #  | "-" -> prefix -
  5288. #  | "*" -> prefix *
  5289. #  | "/" -> prefix /
  5290. #  | "=" -> (fun n m -> if n=m then 1 else 0)
  5291. #  | s -> raise (SemantBug "Unknown primitive");;
  5292. caml_function : string -> int -> int -> int = <fun>
  5293.  
  5294. In the same way as, for parsing, we needed a global environment from which
  5295. the binding depth of identifiers was computed, we need a semantic
  5296. environment from which the interpreter will fetch the value represented by
  5297. identifiers.  The global semantic environment will be a reference on the
  5298. list of predefined ASL values.
  5299.  
  5300. #let init_sem =  map (fun x -> init_semantics(caml_function x))
  5301. #                    init_env;;
  5302. init_sem : semval list =
  5303.  [Funval <fun>; Funval <fun>; Funval <fun>; Funval <fun>; Funval <fun>]
  5304.  
  5305. #let global_sem = ref init_sem;;
  5306. global_sem : semval list ref =
  5307.  ref [Funval <fun>; Funval <fun>; Funval <fun>; Funval <fun>; Funval <fun>]
  5308.  
  5309.  
  5310.  
  5311. 13.2 Semantic functions
  5312.  
  5313. The semantic function is the interpreter itself.  There is one for
  5314. expressions and one for declarations.  The one for expressions computes the
  5315. value of an ASL expression from an environment rho.  The environment will
  5316. contain the values of globally defined ASL values or of temporary ASL
  5317. values.  It is organized as a list, and the numbers representing variable
  5318. occurrences will be used as indices into the environment.
  5319.  
  5320. #let rec nth n = function
  5321. #     []  -> raise (Failure "nth")
  5322. #  | x::l -> if n=1 then x else nth (n-1) l;;
  5323. nth : int -> 'a list -> 'a = <fun>
  5324.  
  5325. #let rec semant rho =
  5326. #  let rec sem = function
  5327. #      Const n -> Constval n
  5328. #    | Var(n) -> nth n rho
  5329. #    | Cond(e1,e2,e3) ->
  5330. #        (match sem e1 with Constval 0 -> sem e3
  5331.  
  5332.  
  5333.                                      93
  5334.  
  5335.  
  5336.  
  5337. #                         | Constval n -> sem e2
  5338. #                         | _ -> raise Illtyped)
  5339. #    | Abs(_,e') -> Funval(fun x -> semant (x::rho) e')
  5340. #    | App(e1,e2) -> (match sem e1
  5341. #                      with Funval(f) -> f (sem e2)
  5342. #                         | _ -> raise Illtyped)
  5343. #  in sem
  5344. #;;
  5345. semant : semval list -> asl -> semval = <fun>
  5346.  
  5347. The main function must be able to treat an ASL declaration, evaluate it, and
  5348. update the global environments (global_env and global_sem).
  5349.  
  5350. #let semantics = function Decl(s,e) ->
  5351. #    let result = semant !global_sem e
  5352. #    in global_env := s::!global_env;
  5353. #       global_sem := result::!global_sem;
  5354. #       print_string "ASL Value of ";
  5355. #       print_string s;
  5356. #       print_string " is ";
  5357. #       (match result with
  5358. #         Constval n -> print_int n
  5359. #       | Funval f -> print_string "<fun>");
  5360. #       print_newline();;
  5361. semantics : top_asl -> unit = <fun>
  5362.  
  5363.  
  5364.  
  5365. 13.3 Examples
  5366.  
  5367. #semantics (parse_top "let f be \\x. + x 1;");;
  5368. ASL Value of f is <fun>
  5369. - : unit = ()
  5370.  
  5371. #semantics (parse_top "let i be \\x. x;");;
  5372. ASL Value of i is <fun>
  5373. - : unit = ()
  5374.  
  5375. #semantics (parse_top "let x be i (f 2);");;
  5376. ASL Value of x is 3
  5377. - : unit = ()
  5378.  
  5379. #semantics (parse_top "let y be if x then (\\x.x) else 2 fi 0;");;
  5380. ASL Value of y is 0
  5381. - : unit = ()
  5382.  
  5383.  
  5384.  
  5385.  
  5386.  
  5387.  
  5388.  
  5389.  
  5390.                                      94
  5391.  
  5392.  
  5393.  
  5394.  
  5395.  
  5396.  
  5397.  
  5398.  
  5399.  
  5400. Chapter 14
  5401.  
  5402.  
  5403.  
  5404. Encoding recursion
  5405.  
  5406.  
  5407.  
  5408.  
  5409. 14.1 Fixpoint combinators
  5410.  
  5411. We have seen that we do not have recursion in ASL. However, it is possible
  5412. to encode recursion by defining a fixpoint combinator.  A fixpoint
  5413. combinator is a function F such that:
  5414.  
  5415.          F M is equivalent to M (F M) modulo the evaluation rules.
  5416.  
  5417. for any expression M.  A consequence of the equivalence given above is that
  5418. fixpoint combinators can encode recursion.  Let us note M=N if expressions
  5419. M and N are equivalent modulo the evaluation rules.  Then, consider ffact to
  5420. be the functional obtained from the body of the factorial function by
  5421. abstracting (i.e.  using as a parameter) the fact identifier, and fix an
  5422. arbitrary fixpoint combinator.  We have:
  5423.  
  5424.     ffact is \fact.(\n. if = n 0 then 1 else * n (fact (- n 1)) fi)
  5425.  
  5426. Now, let us consider the expression E=(fix ffact) 3.  Using our intuition
  5427. about the evaluation rules, and the definition of a fixpoint combinator, we
  5428. obtain:
  5429.        E= ffact (fix ffact) 3
  5430.   Replacing ffact by its definition, we obtain:
  5431.        E= (\fact.(\n. if = n 0 then 1 else * n (fact (- n 1)) fi)) (fix
  5432. ffact) 3
  5433.   We can now pass the two arguments to the first abstraction, instantiating
  5434. fact and n respectively to fix ffact and 3:
  5435.        E= if = 3 0 then 1 else * 3 (fix ffact (- 3 1)) fi
  5436.   We can now reduce the conditional into its else branch:
  5437.        E= * 3 (fix ffact (- 3 1))
  5438.   Continuing this way, we eventually compute:
  5439.        E= * 3 (* 2 (* 1 1)) = 6
  5440.   This is the expected behavior of the factorial function.  Given an
  5441. appropriate fixpoint combinator fix, we could define the factorial function
  5442. as fix ffact, where ffact is the expression above.
  5443.  
  5444.  
  5445.  
  5446.  
  5447.                                      95
  5448.  
  5449.  
  5450.  
  5451.   Unfortunately, when using call-by-value, any application of a fixpoint
  5452. combinator F such that:
  5453.  
  5454.                           F M evaluates to M (F M)
  5455.  
  5456. leads to non-termination of the evaluation (because evaluation of (F M)
  5457. leads to evaluating (M (F M)), and thus (F M) again).
  5458.   We will use the Z fixpoint combinator defined by:
  5459.  
  5460.              Z=lf.((lx. f (ly. (x x) y))(lx. f (ly. (x x) y)))
  5461.  
  5462. The fixpoint combinator Z has the particularity of being usable under
  5463. call-by-value evaluation regime (in order to check that fact, it is
  5464. necessary to know the evaluation rules of l-calculus).  Since the name z
  5465. looks more like an ordinary parameter name, we will call fix the ASL
  5466. expression corresponding to the Z fixpoint combinator.
  5467.  
  5468. #semantics (parse_top
  5469. #        "let fix be \\f.((\\x.f(\\y.(x x) y))(\\x.f(\\y.(x x) y)));");;
  5470. ASL Value of fix is <fun>
  5471. - : unit = ()
  5472.  
  5473. We are now able to define the ASL factorial function:
  5474.  
  5475. #semantics (parse_top
  5476. #        "let fact be fix (\\f.(\\n. if = n 0 then 1
  5477. #                                    else * n (f (- n 1)) fi));");;
  5478. ASL Value of fact is <fun>
  5479. - : unit = ()
  5480.  
  5481. #semantics (parse_top "fact 8;");;
  5482. ASL Value of it is 40320
  5483. - : unit = ()
  5484.  
  5485. and the ASL Fibonacci function:
  5486.  
  5487. #semantics (parse_top
  5488. #        "let fib be fix (\\f.(\\n. if = n 1 then 1
  5489. #                                   else if = n 2 then 1
  5490. #                                        else + (f (- n 1)) (f (-
  5491. n 2)) fi fi));");;
  5492. ASL Value of fib is <fun>
  5493. - : unit = ()
  5494.  
  5495. #semantics (parse_top "fib 9;");;
  5496. ASL Value of it is 34
  5497. - : unit = ()
  5498.  
  5499.  
  5500.  
  5501.  
  5502.  
  5503.  
  5504.                                      96
  5505.  
  5506.  
  5507.  
  5508. 14.2 Recursion as a primitive construct
  5509.  
  5510. Of course, in a more realistic prototype, we would extend the concrete and
  5511. abstract syntaxes of ASL in order to support recursion as a primitive
  5512. construct.  We do not do it here because we want to keep ASL simple.  This
  5513. is an interesting non trivial exercise!
  5514.  
  5515.  
  5516.  
  5517.  
  5518.  
  5519.  
  5520.  
  5521.  
  5522.  
  5523.  
  5524.  
  5525.  
  5526.  
  5527.  
  5528.  
  5529.  
  5530.  
  5531.  
  5532.  
  5533.  
  5534.  
  5535.  
  5536.  
  5537.  
  5538.  
  5539.  
  5540.  
  5541.  
  5542.  
  5543.  
  5544.  
  5545.  
  5546.  
  5547.  
  5548.  
  5549.  
  5550.  
  5551.  
  5552.  
  5553.  
  5554.  
  5555.  
  5556.  
  5557.  
  5558.  
  5559.  
  5560.  
  5561.                                      97
  5562.  
  5563.  
  5564.  
  5565.  
  5566.  
  5567.  
  5568.  
  5569.  
  5570.  
  5571. Chapter 15
  5572.  
  5573.  
  5574.  
  5575. Static typing, polymorphism and type synthesis
  5576.  
  5577.  
  5578.  
  5579. We now want to perform static typechecking of ASL programs, that is, to
  5580. complete typechecking before evaluation, making run-time type tests
  5581. unnecessary during evaluation of ASL programs.
  5582.   Furthermore, we want to have polymorphism (i.e.  allow the identity
  5583. function, for example, to be applicable to any kind of data).
  5584.   Type synthesis may be seen as a game.  When learning a game, we must:
  5585.  
  5586.  -  learn the rules (what is allowed, and what is forbidden);
  5587.  
  5588.  -  learn a winning strategy.
  5589.  
  5590.   In type synthesis, the rules of the game are called a type system, and the
  5591. winning strategy is the typechecking algorithm.
  5592.   In the following sections, we give the ASL type system, the algorithm and
  5593. an implementation of that algorithm.  Most of this presentation is borrowed
  5594. from [7].
  5595.  
  5596.  
  5597. 15.1 The type system
  5598.  
  5599. We study in this section a type system for the ASL language.  Then, we
  5600. present an algorithm performing the type synthesis of ASL programs, and its
  5601. Caml Light implementation.  Because of subtle aspects of the notation used
  5602. (inference rules), and since some important mathematical notions, such as
  5603. unification of first-order terms, are not presented here, this chapter may
  5604. seem obscure at first reading.
  5605.   The type system we will consider for ASL has been first given by Milner
  5606. [27] for a subset of the ML language (in fact, a superset of l-calculus).  A
  5607. type is either:
  5608.  
  5609.  -  the type Number;
  5610.  
  5611.  -  or a type variable (a, b, ...);
  5612.  
  5613.  -  or t1->t2, where t1 and t2 are types.
  5614.  
  5615. In a type, a type variable is an unknown, i.e.  a type that we are
  5616.  
  5617.  
  5618.                                      98
  5619.  
  5620.  
  5621.  
  5622. computing.  We will use t, t', t1, ..., as metavariables(1) representing
  5623. types.  This notation is important:  we shall use other greek letters to
  5624. denote other notions in the following sections.
  5625.  
  5626. Example (a->Number)->b->b is a type.
  5627. O
  5628.   A type scheme, is a type where some variables are distinguished as being
  5629. generic.  We can represent type schemes by:
  5630.  
  5631.                   for all a1,.. .,an.t where t is a type.
  5632.  
  5633. Example
  5634.  
  5635.   for all a.(a->Number)->b->b and (a->Number)->b->b are type schemes.
  5636. O We will use s, s', s1, ..., as metavariables representing type schemes.
  5637.                                           #                   #
  5638. We may also write type schemes as for all a.t.  In this case, a represent a
  5639. (possibly empty) set of generic type variables.  When the set of generic
  5640. variables is empty, we write for all .t or simply t.
  5641.   We will write FV(s) for the set of unknowns occurring in the type scheme
  5642. s.  Unknowns are also called free variables (they are not bound by a
  5643. for all  quantifier).
  5644.   We also write BV(s) (bound type variables of s) for the set of type
  5645. variables occurring in s which are not free (i.e.  the set of variables
  5646. universally quantified).  Bound type variables are also said to be generic.
  5647.  
  5648. Example If s denotes the type scheme for all a.(a->Number)->b->b, then we
  5649. have:
  5650.  
  5651.                                  FV(s)= {b}
  5652.  
  5653. and
  5654.  
  5655.                                  BV(s)= {a}
  5656.  
  5657. O A substitution instance s' of a type scheme s is the type scheme S(s)
  5658. where S is a substitution of types for free type variables appearing in s.
  5659. When applying a substitution to a type scheme, a renaming of some bound type
  5660. variables may become necessary, in order to avoid the capture of a free type
  5661. variable by a quantifier.
  5662.  
  5663. Example
  5664.  
  5665.  -  If s denotes for all b.(b->a)->a and s' is
  5666.     for all b.(b->(g->g))->(g->g), then s' is a substitution instance of s
  5667.  
  5668. ------------------------------
  5669.  1. A  metavariable  should  not be  confused  with  a variable  or  a  type
  5670. variable.
  5671.  
  5672.  
  5673.  
  5674.                                      99
  5675.  
  5676.  
  5677.  
  5678.     because s'= S(s) where S={a<-(g->g)}, i.e.  S substitutes the type g->g
  5679.     for the variable a.
  5680.  
  5681.  -  If s denotes for all b.(b->a)->a and s' is
  5682.     for all d.(d->(b->b))->(b->b), then s' is a substitution instance of s
  5683.     because s'= S(s) where S={a<-(b->b)}.  In this case, the renaming of b
  5684.     into d was necessary:  we did not want the variable b introduced by S to
  5685.     be captured by the universal quantification for all b.
  5686.  
  5687. O The type scheme s'=for all b1 ... bm.t' is said to be a generic instance
  5688. of s=for all a1 ... an.t if there exists a substitution S such that:
  5689.  
  5690.  -  the domain of S is included in {a1,... ,an};
  5691.  
  5692.  -  t'= S(t);
  5693.  
  5694.  -  no bi occurs free in s.
  5695.  
  5696. In other words, a generic instance of a type scheme is obtained by giving
  5697. more precise values to some generic variables, and (possibly) quantifying
  5698. some of the new type variables introduced.
  5699.  
  5700. Example If s=for all b.(b->a)->a, then s' =for all g.((g->g)->a)->a is a
  5701. generic instance of s.  We changed b into (g->g), and we universally
  5702. quantified on the newly introduced type variable g.
  5703. O
  5704.   We express this type system by means of inference rules.  An inference
  5705. rule is written as a fraction:
  5706.  
  5707.  -  the numerator is called the premisses;
  5708.  
  5709.  -  the denominator is called the conclusion.
  5710.  
  5711. An inference rule:
  5712.  
  5713.                                 P1  ...  Pn
  5714.                                 -----------
  5715.                                      C
  5716.  
  5717. may be read in two ways:
  5718.  
  5719.  -  ``If P1, ...and Pn , then C''.
  5720.  
  5721.  -  ``In order to prove C, it is sufficient to prove P1, ...and Pn ''.
  5722.  
  5723. An inference rule may have no premise:  such a rule will be called an axiom.
  5724.  
  5725.  
  5726.  
  5727.  
  5728.  
  5729.  
  5730.                                     100
  5731.  
  5732.  
  5733.  
  5734. A complete proof will be represented by a proof tree of the following form:
  5735.  
  5736.                            Pm  ...       ...  Pk
  5737.                             1                  l
  5738.                           ----               ----
  5739.  
  5740.                                      .
  5741.                                      .
  5742.                                      .
  5743.                               ------... ------
  5744.  
  5745.                                P1   ...   P1
  5746.                                 1          n
  5747.                               ----------------
  5748.  
  5749.                                      C
  5750.  
  5751. where the leaves of the tree (Pm, ..., Pk) are instances of axioms.
  5752.                                1        l
  5753.   In the premisses and the conclusions appear judgements having the form:
  5754.  
  5755.                                  G |- e :s
  5756.  
  5757. Such a judgement should be read as ``under the typing environment G, the
  5758. expression e has type scheme s''.  Typing environments are sets of typing
  5759. hypotheses of the form x:s where x is an identifier name and s is a type
  5760. scheme:  typing environments give types to the variables occurring free
  5761. (i.e.  unbound) in the expression.
  5762.   When typing l-calculus terms, the typing environment is managed as a stack
  5763. (because identifiers possess local scopes).  We represent that fact in the
  5764. presentation of the type system by removing the typing hypothesis concerning
  5765. an identifier name x (if such a typing hypothesis exists) before adding a
  5766. new typing hypothesis concerning x.
  5767.   We write G-G(x) for the set ot typing hypotheses obtained from G by
  5768. removing the typing hypothesis concerning x (if it exists).
  5769. Any numeric constant is of type Number:
  5770.  
  5771.                         --------------------  (NUM)
  5772.                         G |- Const n :Number
  5773.  
  5774. We obtain type schemes for variables from the typing environment G:
  5775.  
  5776.                        ---------------------- (TAUT)
  5777.                        G U {x: s} |- Var x: s
  5778.  
  5779. It is possible to instantiate type schemes.  The ``GenInstance'' relation
  5780. represents generic instantiation.
  5781.  
  5782.                    G |- e :s  s' =GenInstance(s)
  5783.                    -----------------------------  (INST)
  5784.                              G |- e:s'
  5785.  
  5786. It is possible to generalize type schemes with respect to variables that do
  5787. not occur free in the set of hypotheses:
  5788.  
  5789.                       G |- e:s  a not in FV(G)
  5790.                       -------------------------  (GEN)
  5791.                          G |- e:for all a.s
  5792.  
  5793.  
  5794.  
  5795.                                     101
  5796.  
  5797.  
  5798.  
  5799. Typing a conditional:
  5800.  
  5801.                G |- e1 :Number  G |- e2 :t  G |- e3 :t
  5802.                ---------------------------------------  (IF)
  5803.                  G |- (if e1  then e2 else e3 fi): t
  5804.  
  5805. Typing an application:
  5806.  
  5807.                      G |- e1 :t->t'  G |- e2 :t
  5808.                      --------------------------- (APP)
  5809.                           G |- (e1 e2) :t'
  5810.  
  5811. Typing an abstraction:
  5812.  
  5813.                      (G- G(x)) U {x:t} |- e :t'
  5814.                      --------------------------- (ABS)
  5815.                          G |- (lx .e):t->t'
  5816.  
  5817. The special rule below is the one that introduces polymorphism:  this
  5818. corresponds to the ML let construct.
  5819.  
  5820.                G |- e :s  (G -G(x)) U {x: s} |- e': t
  5821.                --------------------------------------  (LET)
  5822.                          G |- (lx .e') e :t
  5823.  
  5824. This type system has been proven to be semantically sound, i.e.  the
  5825. semantic value of a well-typed expression (an expression admitting a type)
  5826. cannot be an error value due to a type error.  This is usually expressed as:
  5827.  
  5828.     Well-typed programs cannot go wrong.
  5829.  
  5830. This fact implies that a clever compiler may produce code without any
  5831. dynamic type test for a well-typed expression.
  5832.  
  5833. Example Let us check, using the set of rules above, that the following is
  5834. true:
  5835.  
  5836.                        0 |- let f =lx.x in f f :b->b
  5837.  
  5838. In order to do so, we will use the equivalence between the let construct and
  5839. an application of an immediate abstraction (i.e.  an expression having the
  5840. following shape:  (lv.M)N.  The (LET) rule will be crucial:  without it, we
  5841. could not check the judgement above.
  5842.  
  5843.  --------------------------- (TAU---------------------- (TAU---------------------- (TAUT)
  5844.         {x: a} |- x: a           G |- f :for all a.a->a     G |- f: for all a.a->a
  5845.  --------------------------- (ABS---------------------- (INS---------------------- (INST)
  5846.       0 |- (lx.x) :a->a          G |- f :(b->b)->(b->b)          G |- f: b->b
  5847.  --------------------------- (GE---------------------------------------------------(APP)
  5848.  0 |- (lx.x) :for all a.a->a            G ={f :for all a.a->a} |- f f :b->b
  5849. ----------------------------------------------------------------------------------- (LET)
  5850.                            0 |- let f =lx.x in f f :b->b
  5851.  
  5852.  
  5853. O
  5854.  
  5855.  
  5856.                                     102
  5857.  
  5858.  
  5859.  
  5860.   This type system does not tell us how to find the best type for an
  5861. expression.  But what is the best type for an expression?  It must be such
  5862. that any other possible type for that expression is more specific; in other
  5863. words, the best type is the most general.
  5864.  
  5865.  
  5866. 15.2 The algorithm
  5867.  
  5868. How do we find the most general type for an expression of our language?  The
  5869. problem with the set of rules above, is that we could instantiate and
  5870. generalize types at any time, introducing type schemes, while the most
  5871. important rules (application and abstraction) used only types.
  5872.   Let us write a new set of inference rules that we will read as an
  5873. algorithm (close to a Prolog program):
  5874. Any numeric constant is of type Number:
  5875.  
  5876.                         --------------------  (NUM)
  5877.                         G |- Const n :Number
  5878.  
  5879. The types of identifiers are obtained by taking generic instances of type
  5880. schemes appearing in the typing environment.  These generic instances will
  5881. be types and not type schemes:  this restriction appears in the rule below,
  5882. where the type t is expected to be a generic instance of the type scheme s.
  5883.   As it is presented (belonging to a deduction system), the following rule
  5884. will have to anticipate the effect of the equality constraints between types
  5885. in the other rules (multiple occurrences of a type metavariable), when
  5886. choosing the instance t.
  5887.  
  5888.                          t =GenInstance(s)
  5889.                        ---------------------- (INST)
  5890.                        G U {x: s} |- Var x: t
  5891.  
  5892. When we read this set of inference rules as an algorithm, the (INST) rule
  5893. will be implemented by:
  5894.  
  5895. 1.  taking as t the ``most general generic instance'' of s that is a type
  5896.     (the rule requires t to be a type and not a type scheme),
  5897.  
  5898. 2.  making t more specific by unification [32] when encountering equality
  5899.     constraints.
  5900.  
  5901. Typing a conditional requires only the test part to be of type Number, and
  5902. both alternatives to be of the same type t.  This is an example of equality
  5903. constraint between the types of two expressions.
  5904.  
  5905.               G |- e1 :Number  G |- e2 :t  G |- e3 :t
  5906.               ---------------------------------------  (COND)
  5907.                 G |- (if e1  then e2 else e3 fi): t
  5908.  
  5909. Typing an application produces also equality constraints that are to be
  5910.  
  5911.  
  5912.  
  5913.  
  5914.  
  5915.  
  5916.                                     103
  5917.  
  5918.  
  5919.  
  5920. solved by unification:
  5921.  
  5922.                      G |- e1 :t->t'  G |- e2 :t
  5923.                      --------------------------- (APP)
  5924.                           G |- (e1 e2) :t'
  5925.  
  5926. Typing an abstraction ``pushes'' a typing hypothesis for the abstracted
  5927. identifier:  unification will make it more precise during the typing of the
  5928. abstraction body:
  5929.  
  5930.                 (G -G(x)) U {x: for all .t} |- e: t'
  5931.                 ------------------------------------  (ABS)
  5932.                          G |- (lx .e):t->t'
  5933.  
  5934. Typing a let construct involves a generalization step:  we generalize as
  5935. much as possible.
  5936.  
  5937. G |- e: t'  {a ,.. .,a } =FV(t') -FV(G)  (G- G(x)) U {x: for all a ... a .t'} |- e': t
  5938.               1       n                                           1     n
  5939. --------------------------------------------------------------------------------------  (LET)
  5940.                                   G |- (lx .e') e: t
  5941.  
  5942.   This set of inference rules represents an algorithm because there is
  5943. exactly one conclusion for each syntactic ASL construct (giving priority to
  5944. the (LET) rule over the regular application rule).  This set of rules may be
  5945. read as a Prolog program.
  5946.   This algorithm has been proven to be:
  5947.  
  5948.  -  syntactically sound:  when the algorithm succeeds on an expression e and
  5949.     returns a type t, then e:t.
  5950.  
  5951.  -  complete:  if an expression e possesses a type t, then the algorithm
  5952.     will find a type t' such that t is an instance of t'.  The returned
  5953.     type t' is thus the most general type of e.
  5954.  
  5955. Example
  5956.  
  5957.   We compute the type that we simply checked in our last example.  What is
  5958. drawn below is the result of the type synthesis:  in fact, we run our
  5959. algorithm with type variables representing unknowns, modifying the previous
  5960. applications of the (INST) rule when necessary (i.e.  when encountering an
  5961. equality constraint).  This is valid, since it can be proved that the
  5962. correction of the whole deduction tree is preserved by substitution of types
  5963. for type variables.  In a real implementation of the algorithm, the data
  5964. structures representing types will be submitted to a unification mechanism.
  5965.  
  5966.        ----------------- (INS---------------------- (INS------------(INST)
  5967.         {x :a} |- x :a       G |- f: (b->b)->(b->b)     G |- f:b->b
  5968.        ----------------- (AB-----------------------------------------(APP)
  5969.        0 |- (lx.x): a->a       G= {f: for all a.a->a} |- f f: b->b
  5970.       --------------------------------------------------------------- (LET)
  5971.                        0 |- let f =lx.x in f f :b->b
  5972.  
  5973.  
  5974.  
  5975.  
  5976.                                     104
  5977.  
  5978.  
  5979.  
  5980.  Once again, this expression is not typable without the use of the (LET)
  5981. rule:  an error would occur because of the type equality constraints between
  5982. all occurrences of a variable bound by a ``l''.  In an effective
  5983. implementation, a unification error would occur.
  5984. O
  5985.   We may notice from the example above that the algorithm is
  5986. syntax-directed:  since, for a given expression, a type deduction for that
  5987. expression uses exactly one rule per sub-expression, the deduction possesses
  5988. the same structure as the expression.  We can thus reconstruct the ASL
  5989. expression from its type deduction tree.  From the deduction tree above, if
  5990. we write upper rules as being ``arguments'' of the ones below and if we
  5991. annotate the applications of the (INST) and (ABS) rules by the name of the
  5992. subject variable, we obtain:
  5993.  
  5994.                    LETf(ABSx(INSTx),  APP(INSTf, INSTf))
  5995.  
  5996. This is an illustration of the ``types-as-propositions and
  5997. programs-as-proofs'' paradigm, also known as the ``Curry-Howard
  5998. isomorphism'' (cf.  [14]).  In this example, we can see the type of the
  5999. considered expression as a proposition and the expression itself as the
  6000. proof, and, indeed, we recognize the expression as the deduction tree.
  6001.  
  6002.  
  6003. 15.3 The ASL type-synthesizer
  6004.  
  6005. We now implement the set of inference rules given above.
  6006.   We need:
  6007.  
  6008.  -  a Caml representation of ASL types and type schemes,
  6009.  
  6010.  -  a management of type environments,
  6011.  
  6012.  -  a unification procedure,
  6013.  
  6014.  -  a typing algorithm.
  6015.  
  6016. 15.3.1 Representation of ASL types and type schemes
  6017.  
  6018. We first need to define a Caml type for our ASL type data structure:
  6019.  
  6020. #type asl_type = Unknown
  6021. #              | Number
  6022. #              | TypeVar of vartype
  6023. #              | Arrow of asl_type * asl_type
  6024. #and vartype = {Index:int; mutable Value:asl_type}
  6025. #and asl_type_scheme = Forall of int list * asl_type ;;
  6026. Type asl_type defined.
  6027. Type vartype defined.
  6028. Type asl_type_scheme defined.
  6029.  
  6030. The Unknown ASL type is not really a type:  it is the initial value of fresh
  6031.  
  6032.  
  6033.                                     105
  6034.  
  6035.  
  6036.  
  6037. ASL type variables.  We will consider as abnormal a situation where Unknown
  6038. appears in place of a regular ASL type.  In such situations, we will raise
  6039. the following exception:
  6040.  
  6041. #exception TypingBug of string;;
  6042. Exception TypingBug defined.
  6043.  
  6044. Type variables are allocated by the new_vartype function, and their global
  6045. counter (a local reference) is reset by reset_vartypes.
  6046.  
  6047. #let new_vartype, reset_vartypes =
  6048. #(* Generating and resetting unknowns *)
  6049. #    let counter = ref 0
  6050. #    in (function () -> counter := !counter + 1;
  6051. #                       {Index = !counter; Value = Unknown}),
  6052. #       (function () -> counter := 0);;
  6053. new_vartype : unit -> vartype = <fun>
  6054. reset_vartypes : unit -> unit = <fun>
  6055.  
  6056.  
  6057. 15.3.2 Destructive unification of ASL types
  6058.  
  6059. We will need to ``shorten'' type variables:  since they are indirections to
  6060. ASL types, we need to follow these indirections in order to obtain the type
  6061. that they represent.  For the sake of efficiency, we take advantage of this
  6062. operation to replace multiple indirections by single indirections
  6063. (shortening).
  6064.  
  6065. #let rec shorten t =
  6066. #    match t with
  6067. #     TypeVar {Index=_; Value=Unknown} -> t
  6068. #   | TypeVar ({Index=_;
  6069. #                Value=TypeVar {Index=_;
  6070. #                               Value=Unknown} as tv}) -> tv
  6071. #   | TypeVar ({Index=_; Value=TypeVar tv1} as tv2)
  6072. #            -> tv2.Value <- tv1.Value; shorten t
  6073. #   | TypeVar {Index=_; Value=t'} -> t'
  6074. #   | Unknown -> raise (TypingBug "shorten")
  6075. #   | t' -> t';;
  6076. shorten : asl_type -> asl_type = <fun>
  6077.  
  6078. An ASL type error will be represented by the following exception:
  6079.  
  6080. #exception TypeClash of asl_type * asl_type;;
  6081. Exception TypeClash defined.
  6082.  
  6083. We will need unification on ASL types with occur-check.  The following
  6084. function implements occur-check:
  6085.  
  6086. #let occurs {Index=n;Value=_} =
  6087. #  let rec occrec = function
  6088.  
  6089.  
  6090.                                     106
  6091.  
  6092.  
  6093.  
  6094. #        TypeVar{Index=m;Value=_} -> (n=m)
  6095. #      | Number -> false
  6096. #      | Arrow(t1,t2) -> (occrec t1) or (occrec t2)
  6097. #      | Unknown -> raise (TypingBug "occurs")
  6098. #  in occrec
  6099. #;;
  6100. occurs : vartype -> asl_type -> bool = <fun>
  6101.  
  6102. The unification function:  implements destructive unification.  Instead of
  6103. returning the most general unifier, it returns the unificand of two types
  6104. (their most general common instance).  The two arguments are physically
  6105. modified in order to represent the same type.  The unification function will
  6106. detect type clashes.
  6107.  
  6108. #let rec unify (tau1,tau2) =
  6109. #  match (shorten tau1, shorten tau2)
  6110. #  with (* type variable n and type variable m *)
  6111. #       (TypeVar({Index=n; Value=Unknown} as tv1) as t1),
  6112. #       (TypeVar({Index=m; Value=Unknown} as tv2) as t2)
  6113. #           -> if n <> m then tv1.Value <- t2
  6114. #     | (* type t1 and type variable *)
  6115. #      t1, (TypeVar ({Index=_;Value=Unknown} as tv) as t2)
  6116. #            -> if not(occurs tv t1) then tv.Value <- t1
  6117. #               else raise (TypeClash (t1,t2))
  6118. #     | (* type variable and type t2 *)
  6119. #       (TypeVar ({Index=_;Value=Unknown} as tv) as t1), t2
  6120. #            -> if not(occurs tv t2) then tv.Value <- t2
  6121. #               else raise (TypeClash (t1,t2))
  6122. #     | Number, Number -> ()
  6123. #     | Arrow(t1,t2), (Arrow(t'1,t'2) as t)
  6124. #            -> unify(t1,t'1); unify(t2,t'2)
  6125. #     | (t1,t2) -> raise (TypeClash (t1,t2));;
  6126. unify : asl_type * asl_type -> unit = <fun>
  6127.  
  6128.  
  6129. 15.3.3 Representation of typing environments
  6130.  
  6131. We use asl_type_scheme list as typing environments, and we will use the
  6132. encoding of variables as indices into the environment.
  6133.   The initial environment is a list of types (Number -> (Number -> Number)),
  6134. which are the types of the ASL primitive functions.
  6135.  
  6136. #let init_typing_env =
  6137. #    map (function s ->
  6138. #            Forall([],Arrow(Number,
  6139. #                              Arrow(Number,Number))))
  6140. #        init_env;;
  6141.  
  6142. The global typing environment is initialized to the initial typing
  6143. environment, and will be updated with the type of each ASL declaration,
  6144. after they are type-checked.
  6145.  
  6146.  
  6147.                                     107
  6148.  
  6149.  
  6150.  
  6151. #let global_typing_env = ref init_typing_env;;
  6152.  
  6153.  
  6154. 15.3.4 From types to type schemes:  generalization
  6155.  
  6156. In order to implement generalization, we will need some functions collecting
  6157. types variables occurring in ASL types.
  6158.   The following function computes the list of type variables of its
  6159. argument.
  6160.  
  6161. #let vars_of_type tau =
  6162. # let rec vars vs = function
  6163. #       Number -> vs
  6164. #     | TypeVar {Index=n; Value=Unknown}
  6165. #                 -> if mem n vs then vs else n::vs
  6166. #     | TypeVar {Index=_; Value= t} -> vars vs t
  6167. #     | Arrow(t1,t2) -> vars (vars vs t1) t2
  6168. #     | Unknown -> raise (TypingBug "vars_of_type")
  6169. #  in vars [] tau
  6170. #;;
  6171. vars_of_type : asl_type -> int list = <fun>
  6172.  
  6173. The unknowns_of_type(bv,t) application returns the list of variables
  6174. occurring in t that do not appear in bv.  The subtract function returns the
  6175. difference of two lists.
  6176.  
  6177. #let unknowns_of_type (bv,t) =
  6178. #    subtract (vars_of_type t) bv;;
  6179. unknowns_of_type : int list * asl_type -> int list = <fun>
  6180.  
  6181. We need to compute the list of unknowns of a type environment for the
  6182. generalization process (unknowns belonging to that list cannot become
  6183. generic).  The set of unknowns of a type environment is the union of the
  6184. unknowns of each type.  The flat function flattens a list of lists.
  6185.  
  6186. #let flat = it_list (prefix @) [];;
  6187. flat : '_a list list -> '_a list = <fun>
  6188.  
  6189. #let unknowns_of_type_env env =
  6190. #    flat (map (function Forall(gv,t) -> unknowns_of_type (gv,t)) env);;
  6191. unknowns_of_type_env : asl_type_scheme list -> int list = <fun>
  6192.  
  6193. The generalization of a type is relative to a typing environment.  The
  6194. make_set function eliminates duplicates in its list argument.
  6195.  
  6196. #let rec make_set = function
  6197. #     []  -> []
  6198. #  | x::l -> if mem x l then make_set l else x :: make_set l;;
  6199. make_set : 'a list -> 'a list = <fun>
  6200.  
  6201. #let generalise_type (gamma, tau) =
  6202.  
  6203.  
  6204.                                     108
  6205.  
  6206.  
  6207.  
  6208. #  let genvars =
  6209. #        make_set (subtract (vars_of_type tau)
  6210. #                           (unknowns_of_type_env gamma))
  6211. #  in Forall(genvars, tau)
  6212. #;;
  6213. generalise_type : asl_type_scheme list * asl_type -> asl_type_scheme = <fun>
  6214.  
  6215.  
  6216. 15.3.5 From type schemes to types:  generic instantiation
  6217.  
  6218. The following function returns a generic instance of its type scheme
  6219. argument.  A generic instance is obtained by replacing all generic type
  6220. variables by new unknowns:
  6221.  
  6222. #let gen_instance (Forall(gv,tau)) =
  6223. #  (* We associate a new unknown to each generic variable *)
  6224. #  let unknowns = map (function n -> n, TypeVar(new_vartype())) gv in
  6225. #  let rec ginstance = function
  6226. #        (TypeVar {Index=n; Value=Unknown} as t) ->
  6227. #                    (try assoc n unknowns
  6228. #                     with Not_found -> t)
  6229. #      | TypeVar {Index=_; Value= t} -> ginstance t
  6230. #      | Number -> Number
  6231. #      | Arrow(t1,t2) -> Arrow(ginstance t1, ginstance t2)
  6232. #      | Unknown -> raise (TypingBug "gen_instance")
  6233. #  in ginstance tau
  6234. #;;
  6235. gen_instance : asl_type_scheme -> asl_type = <fun>
  6236.  
  6237.  
  6238. 15.3.6 The ASL type synthesizer
  6239.  
  6240. The type synthesizer is the asl_typing_expr function.  Each of its match
  6241. cases corresponds to an inference rule given above.
  6242.  
  6243. #let rec asl_typing_expr gamma =
  6244. #  let rec type_rec = function
  6245. #      Const _ -> Number
  6246. #    | Var n ->
  6247. #        let sigma =
  6248. #          try nth n gamma
  6249. #          with Failure _ -> raise (TypingBug "Unbound")
  6250. #        in gen_instance sigma
  6251. #    | Cond (e1,e2,e3) ->
  6252. #        unify(Number, type_rec e1);
  6253. #        let t2 = type_rec e2 and t3 = type_rec e3
  6254. #        in unify(t2, t3); t3
  6255. #    | App((Abs(x,e2) as f), e1) -> (* LET case *)
  6256. #        let t1 = type_rec e1 in
  6257. #          let sigma = generalise_type (gamma,t1)
  6258. #        in asl_typing_expr (sigma::gamma) e2
  6259.  
  6260.  
  6261.                                     109
  6262.  
  6263.  
  6264.  
  6265. #    | App(e1,e2) ->
  6266. #        let u = TypeVar(new_vartype())
  6267. #        in unify(type_rec e1,Arrow(type_rec e2,u)); u
  6268. #    | Abs(x,e) ->
  6269. #        let u = TypeVar(new_vartype()) in
  6270. #        let s = Forall([],u)
  6271. #        in Arrow(u,asl_typing_expr (s::gamma) e)
  6272. #  in type_rec;;
  6273. asl_typing_expr : asl_type_scheme list -> asl -> asl_type = <fun>
  6274.  
  6275.  
  6276. 15.3.7 Typing, trapping type clashes and printing ASL types
  6277.  
  6278. Now, we define some auxiliary functions in order to build a ``good-looking''
  6279. type synthesizer.  First of all, a printing routine for ASL type schemes is
  6280. defined (using a function tvar_name which computes a decent name for type
  6281. variables).
  6282.  
  6283. #let tvar_name n =
  6284. # (* Computes a name "'a", ... for type variables, *)
  6285. # (* given an integer n representing the position  *)
  6286. # (* of the type variable in the list of generic   *)
  6287. # (* type variables                                *)
  6288. # let rec name_of n =
  6289. #    let q,r = (n / 26), (n mod 26) in
  6290. #    let s = make_string 1 (char_of_int (96+r)) in
  6291. #    if q=0 then s else (name_of q)^s
  6292. # in "'"^(name_of n)
  6293. #;;
  6294. tvar_name : int -> string = <fun>
  6295.  
  6296. Then a printing function for type schemes.
  6297.  
  6298. #let print_type_scheme (Forall(gv,t)) =
  6299. # (* Prints a type scheme.               *)
  6300. # (* Fails when it encounters an unknown *)
  6301. # let names = let rec names_of = function
  6302. #                   (n,[]) -> []
  6303. #                 | (n,(v1::Lv)) -> (tvar_name n)::(names_of (n+1, Lv))
  6304. #             in names_of (1,gv) in
  6305. # let tvar_names = combine (rev gv, names) in
  6306. # let rec print_rec = function
  6307. #      TypeVar{Index=n; Value=Unknown} ->
  6308. #         let name = try assoc n tvar_names
  6309. #                    with Not_found ->
  6310. #                             raise (TypingBug "Non generic variable")
  6311. #         in print_string name
  6312. #    | TypeVar{Index=_;Value=t} -> print_rec t
  6313. #    | Number -> print_string "Number"
  6314. #    | Arrow(t1,t2) ->
  6315. #           print_string "("; print_rec t1;
  6316.  
  6317.  
  6318.                                     110
  6319.  
  6320.  
  6321.  
  6322. #           print_string " -> "; print_rec t2;
  6323. #           print_string ")"
  6324. #    | Unknown -> raise (TypingBug "print_type_scheme")
  6325. # in print_rec t
  6326. #;;
  6327. Toplevel input:
  6328. >                 | (n,(v1::Lv)) -> (tvar_name n)::(names_of (n+1, Lv))
  6329. >                           ^^
  6330. Warning: the variable Lv starts with an upper case letter in this pattern.
  6331. print_type_scheme : asl_type_scheme -> unit = <fun>
  6332.  
  6333. Now, the main function which resets the type variables counter, calls the
  6334. type synthesizer, traps ASL type clashes and prints the resulting types.  At
  6335. the end, the global environments are updated.
  6336.  
  6337. #let typing (Decl(s,e)) =
  6338. # reset_vartypes();
  6339. # let tau = (* TYPING *)
  6340. #     try asl_typing_expr !global_typing_env e
  6341. #     with TypeClash(t1,t2) -> (* A typing error *)
  6342. #           let vars=vars_of_type(t1)@vars_of_type(t2) in
  6343. #           print_string "ASL Type clash between ";
  6344. #           print_type_scheme (Forall(vars,t1));
  6345. #           print_string " and ";
  6346. #           print_type_scheme (Forall(vars,t2));
  6347. #           print_newline();
  6348. #           raise (Failure "ASL typing") in
  6349. # let sigma = generalise_type (!global_typing_env,tau) in
  6350. # (* UPDATING ENVIRONMENTS *)
  6351. # global_env := s::!global_env;
  6352. # global_typing_env := sigma::!global_typing_env;
  6353. # reset_vartypes ();
  6354. # (* PRINTING RESULTING TYPE *)
  6355. # print_string "ASL Type of ";
  6356. # print_string s;
  6357. # print_string " is ";
  6358. # print_type_scheme sigma; print_newline();;
  6359. typing : top_asl -> unit = <fun>
  6360.  
  6361.  
  6362. 15.3.8 Typing ASL programs
  6363.  
  6364. We reinitialize the parsing environment:
  6365.  
  6366. #global_env:=init_env; ();;
  6367. - : unit = ()
  6368.  
  6369. Now, let us run some examples through the ASL type checker:
  6370.  
  6371. #typing (parse_top "let x be 1;");;
  6372. ASL Type of x is Number
  6373.  
  6374.  
  6375.                                     111
  6376.  
  6377.  
  6378.  
  6379. - : unit = ()
  6380.  
  6381. #typing (parse_top "+ 2 ((\\x.x) 3);");;
  6382. ASL Type of it is Number
  6383. - : unit = ()
  6384.  
  6385. #typing (parse_top "if + 0 1 then 1 else 0 fi;");;
  6386. ASL Type of it is Number
  6387. - : unit = ()
  6388.  
  6389. #typing (parse_top "let id be \\x.x;");;
  6390. ASL Type of id is ('a -> 'a)
  6391. - : unit = ()
  6392.  
  6393. #typing (parse_top "+ (id 1) (id id 2);");;
  6394. ASL Type of it is Number
  6395. - : unit = ()
  6396.  
  6397. #typing (parse_top "let f be (\\x.x x) (\\x.x);");;
  6398. ASL Type of f is ('a -> 'a)
  6399. - : unit = ()
  6400.  
  6401. #typing (parse_top "+ (\\x.x) 1;");;
  6402. ASL Type clash between Number and ('a -> 'a)
  6403. Uncaught exception: Failure "ASL typing"
  6404.  
  6405.  
  6406. 15.3.9 Typing and recursion
  6407.  
  6408. The Z fixpoint combinator does not have a type in Milner's type system:
  6409.  
  6410. #typing (parse_top
  6411. #  "let fix be \\f.((\\x.f(\\z.(x x)z)) (\\x.f(\\z.(x x)z)));");;
  6412. ASL Type clash between 'a and ('a -> 'b)
  6413. Uncaught exception: Failure "ASL typing"
  6414.  
  6415. This is because we try to apply x to itself, and the type of x is not
  6416. polymorphic.  In fact, no fixpoint combinator is typable in ASL. This is why
  6417. we need a special primitive or syntactic construct in order to express
  6418. recursivity.
  6419.   If we want to assign types to recursive programs, we have to predefine the
  6420. Z fixpoint combinator.  Its type scheme should be for all a.((a->a)->a),
  6421. because we take fixpoints of functions.
  6422.  
  6423. #global_env := "fix"::init_env;
  6424. #global_typing_env:=
  6425. #    (Forall([1],
  6426. #     Arrow(Arrow(TypeVar{Index=1;Value=Unknown},
  6427. #                   TypeVar{Index=1;Value=Unknown}),
  6428. #            TypeVar{Index=1;Value=Unknown})))
  6429. #   ::init_typing_env;
  6430.  
  6431.  
  6432.                                     112
  6433.  
  6434.  
  6435.  
  6436. #();;
  6437. - : unit = ()
  6438.  
  6439. We can now define our favorite functions as:
  6440.  
  6441. #typing (parse_top
  6442. #    "let fact be fix (\\f.(\\n. if = n 0 then 1
  6443. #                            else * n (f (- n 1))
  6444. #                            fi));");;
  6445. ASL Type of fact is (Number -> Number)
  6446. - : unit = ()
  6447.  
  6448. #typing (parse_top "fact 8;");;
  6449. ASL Type of it is Number
  6450. - : unit = ()
  6451.  
  6452. #typing (parse_top
  6453. #  "let fib be fix (\\f.(\\n. if = n 1 then 1
  6454. #                             else if = n 2 then 1
  6455. #                                  else + (f(- n 1)) (f(- n 2))
  6456. #                                  fi
  6457. #                             fi));");;
  6458. ASL Type of fib is (Number -> Number)
  6459. - : unit = ()
  6460.  
  6461. #typing (parse_top "fib 9;");;
  6462. ASL Type of it is Number
  6463. - : unit = ()
  6464.  
  6465.  
  6466.  
  6467.  
  6468.  
  6469.  
  6470.  
  6471.  
  6472.  
  6473.  
  6474.  
  6475.  
  6476.  
  6477.  
  6478.  
  6479.  
  6480.  
  6481.  
  6482.  
  6483.  
  6484.  
  6485.  
  6486.  
  6487.  
  6488.  
  6489.                                     113
  6490.  
  6491.  
  6492.  
  6493.  
  6494.  
  6495.  
  6496.  
  6497.  
  6498.  
  6499. Chapter 16
  6500.  
  6501.  
  6502.  
  6503. Compiling ASL to an abstract machine code
  6504.  
  6505.  
  6506.  
  6507. In order to fully take advantage of the static typing of ASL programs, we
  6508. have to:
  6509.  
  6510.  -  either write a new interpreter without type tests (difficult, because we
  6511.     used pattern-matching in order to realize type tests);
  6512.  
  6513.  -  or design an untyped machine and produce code for it.
  6514.  
  6515. We choose here the second solution:  it will permit us to give some
  6516. intuition about the compiling process of functional languages, and to
  6517. describe a typical execution model for (strict) functional languages.  The
  6518. machine that we will use is a simplified version the Categorical Abstract
  6519. Machine (CAM, for short).
  6520.   We will call CAM our abstract machine, despite its differences with the
  6521. original CAM. For more informations on the CAM, see [8, 26].
  6522.  
  6523.  
  6524. 16.1 The Abstract Machine
  6525.  
  6526. The execution model is a stack machine (i.e.  a machine using a stack).  In
  6527. this section, we define in Caml the states of the CAM and its instructions.
  6528.   A state is composed of:
  6529.  
  6530.  -  a register (holding values and environments),
  6531.  
  6532.  -  a program counter, represented here as a list of instructions whose
  6533.     first element is the current instruction being executed,
  6534.  
  6535.  -  and a stack represented as a list of code addresses (instruction lists),
  6536.     values and environments.
  6537.  
  6538. The first Caml type that we need is the type for CAM instructions.  We will
  6539. study later the effect of each instruction.
  6540.  
  6541. #type instruction =
  6542. #  Quote of int               (* Integer constants *)
  6543. #| Plus | Minus               (* Arithmetic operations *)
  6544.  
  6545.  
  6546.                                     114
  6547.  
  6548.  
  6549.  
  6550. #| Divide | Equal | Times
  6551. #| Nth of int                 (* Variable accesses *)
  6552. #| Branch of instruction list * instruction list
  6553. #                             (* Conditional execution *)
  6554. #| Push                       (* Pushes onto the stack *)
  6555. #| Swap                       (* Exch. top of stack and register *)
  6556. #| Clos of instruction list   (* Builds a closure with the current environ-
  6557. ment *)
  6558. #| Apply                      (* Function application *)
  6559. #;;
  6560. Type instruction defined.
  6561.  
  6562. We need a new type for semantic values since instruction lists have now
  6563. replaced abstract syntax trees.  The semantic values are merged in a type
  6564. object.  The type object behaves as data in a computer memory:  we need
  6565. higher-level information (such as type information) in order to interpret
  6566. them.  Furthermore, some data do not correspond to anything (for example an
  6567. environment composed of environments represents neither an ASL value nor an
  6568. intermediate data in a legal computation process).
  6569.  
  6570. #type object = Constant of int
  6571. #            | Closure of object * object
  6572. #            | Address of instruction list
  6573. #            | Environment of object list
  6574. #;;
  6575. Type object defined.
  6576.  
  6577. The type state is a product type with mutable components.
  6578.  
  6579. #type state = {mutable Reg: object;
  6580. #              mutable PC: instruction list;
  6581. #              mutable Stack: object list}
  6582. #;;
  6583. Type state defined.
  6584.  
  6585. Now, we give the operational semantics of CAM instructions.  The effect of
  6586. an instruction is to change the state configuration.  This is what we
  6587. describe now with the step function.  Code executions will be arbitrary
  6588. iterations of this function.
  6589.  
  6590. #exception CAMbug of string;;
  6591. Exception CAMbug defined.
  6592.  
  6593. #exception CAM_End of object;;
  6594. Exception CAM_End defined.
  6595.  
  6596. #let step state = match state with
  6597. #  {Reg=_; PC=Quote(n)::code; Stack=s} ->
  6598. #                state.Reg <- Constant(n); state.PC <- code
  6599. #
  6600. #| {Reg=Constant(m); PC=Plus::code; Stack=Constant(n)::s} ->
  6601.  
  6602.  
  6603.                                     115
  6604.  
  6605.  
  6606.  
  6607. #                state.Reg <- Constant(n+m); state.Stack <- s;
  6608. #                state.PC <- code
  6609. #
  6610. #| {Reg=Constant(m); PC=Minus::code; Stack=Constant(n)::s} ->
  6611. #                state.Reg <- Constant(n-m); state.Stack <- s;
  6612. #                state.PC <- code
  6613. #
  6614. #| {Reg=Constant(m); PC=Times::code; Stack=Constant(n)::s} ->
  6615. #                state.Reg <- Constant(n*m); state.Stack <- s;
  6616. #                state.PC <- code
  6617. #
  6618. #| {Reg=Constant(m); PC=Divide::code; Stack=Constant(n)::s} ->
  6619. #                state.Reg <- Constant(n/m); state.Stack <- s;
  6620. #                state.PC <- code
  6621. #
  6622. #| {Reg=Constant(m); PC=Equal::code; Stack=Constant(n)::s} ->
  6623. #                state.Reg <- Constant(if n=m then 1 else 0);
  6624. #                state.Stack <- s; state.PC <- code
  6625. #
  6626. #| {Reg=Constant(m); PC=Branch(code1,code2)::code; Stack=r::s} ->
  6627. #                state.Reg <- r;
  6628. #                state.Stack <- Address(code)::s;
  6629. #                state.PC <- (if m=0 then code2 else code1)
  6630. #
  6631. #| {Reg=r; PC=Push::code; Stack=s} ->
  6632. #                state.Stack <- r::s; state.PC <- code
  6633. #
  6634. #| {Reg=r1; PC=Swap::code; Stack=r2::s} ->
  6635. #                state.Reg <- r2; state.Stack <- r1::s;
  6636. #                state.PC <- code
  6637. #
  6638. #| {Reg=r; PC=Clos(code1)::code; Stack=s} ->
  6639. #                state.Reg <- Closure(Address(code1),r);
  6640. #                state.PC <- code
  6641. #
  6642. #| {Reg=_; PC=[]; Stack=Address(code)::s} ->
  6643. #                state.Stack <- s; state.PC <- code
  6644. #
  6645. #| {Reg=v; PC=Apply::code;
  6646. #          Stack=Closure(Address(code1),Environment(e))::s} ->
  6647. #                state.Reg <- Environment(v::e);
  6648. #                state.Stack <- Address(code)::s;
  6649. #                state.PC <- code1
  6650. #
  6651. #| {Reg=v; PC=[]; Stack=[]} ->
  6652. #                raise (CAM_End v)
  6653. #| {Reg=_; PC=(Plus|Minus|Times|Divide|Equal)::code; Stack=_::_} ->
  6654. #                raise (CAMbug "IllTyped")
  6655. #
  6656. #| {Reg=Environment(e); PC=Nth(n)::code; Stack=_} ->
  6657. #                state.Reg <- (try nth n e
  6658.  
  6659.  
  6660.                                     116
  6661.  
  6662.  
  6663.  
  6664. #                              with Failure _ -> raise (CAMbug "IllTyped"));
  6665. #                state.PC <- code
  6666. #| _ -> raise (CAMbug "Wrong configuration")
  6667. #;;
  6668. step : state -> unit = <fun>
  6669.  
  6670. We may notice that the empty code sequence denotes a (possibly final) return
  6671. instruction.
  6672.   We could argue that pattern-matching in the Camlstep function implements a
  6673. kind of dynamic typechecking.  In fact, in a concrete (low-level)
  6674. implementation of the machine (expansion of the CAM instructions in assembly
  6675. code, for example), these tests would not appear.  They are useless since we
  6676. trust the typechecker and the compiler.  So, any execution error in a real
  6677. implementation comes from a bug in one of the above processes and would lead
  6678. to memory errors or illegal instructions (usually detected by the computer's
  6679. operating system).
  6680.  
  6681.  
  6682. 16.2 Compiling ASL programs into CAM code
  6683.  
  6684. We give in this section a compiling function taking the abstract syntax tree
  6685. of an ASL expression and producing CAM code.  The compilation scheme is very
  6686. simple:
  6687.  
  6688.  -  the code of a constant is Quote;
  6689.  
  6690.  -  a variable is compiled as an access to the appropriate component of the
  6691.     current environment (Nth);
  6692.  
  6693.  -  the code of a conditional expression will save the current environment
  6694.     (Push), evaluate the condition part, and, according to the boolean value
  6695.     obtained, select the appropriate code to execute (Branch);
  6696.  
  6697.  -  the code of an application will also save the environment on the stack
  6698.     (Push), execute the function part of the application, then exchange the
  6699.     functional value and the saved environment (Swap), evaluate the argument
  6700.     and, finally, apply the functional value (which is at the top of the
  6701.     stack) to the argument held in the register with the Apply instruction;
  6702.  
  6703.  -  the code of an abstraction simply consists in building a closure
  6704.     representing the functional value:  the closure is composed of the code
  6705.     of the function and the current environment.
  6706.  
  6707. Here is the compiling function:
  6708.  
  6709. #let rec code_of = function
  6710. #  Const(n) -> [Quote(n)]
  6711. #| Var n -> [Nth(n)]
  6712. #| Cond(e_test,e_t,e_f) ->
  6713. #         Push::(code_of e_test)
  6714. #       @[Branch(code_of e_t, code_of e_f)]
  6715.  
  6716.  
  6717.                                     117
  6718.  
  6719.  
  6720.  
  6721. #| App(e1,e2) -> Push::(code_of e1)
  6722. #               @[Swap]@(code_of e2)
  6723. #               @[Apply]
  6724. #| Abs(_,e) -> [Clos(code_of e)];;
  6725. code_of : asl -> instruction list = <fun>
  6726.  
  6727. A global environment is needed in order to maintain already defined values.
  6728. Any CAM execution will start in a state whose register part contains this
  6729. global environment.
  6730.  
  6731. #let init_CAM_env =
  6732. #  let basic_instruction = function
  6733. #        "+" -> Plus
  6734. #      | "-" -> Minus
  6735. #      | "*" -> Times
  6736. #      | "/" -> Divide
  6737. #      | "=" -> Equal
  6738. #      | s -> raise (CAMbug "Unknown primitive")
  6739. #  in map (function s ->
  6740. #           Closure(Address[Clos(Push::Nth(2)
  6741. #                                 ::Swap::Nth(1)
  6742. #                                 ::[basic_instruction s])],
  6743. #                    Environment []))
  6744. #         init_env;;
  6745. init_CAM_env : object list =
  6746.  [Closure (Address [Clos [Push; Nth 2; Swap; Nth 1; Plus]], Environment []);
  6747.  Closure (Address [Clos [Push; Nth 2; Swap; Nth 1; Minus]], Environment []);
  6748. Closure (Address [Clos [Push; Nth 2; Swap; Nth 1; Times]], Environment []);
  6749. Closure (Address [Clos [Push; Nth 2; Swap; Nth 1; Divide]], Environment []);
  6750. Closure (Address [Clos [Push; Nth 2; Swap; Nth 1; Equal]], Environment [])]
  6751.  
  6752. #let global_CAM_env = ref init_CAM_env;;
  6753. global_CAM_env : object list ref =
  6754.  ref
  6755.   [Closure (Address [Clos [Push; Nth 2; Swap; Nth 1; Plus]], Environ-
  6756. ment []);
  6757.   Closure (Address [Clos [Push; Nth 2; Swap; Nth 1; Minus]], Environ-
  6758. ment []);
  6759.  Closure (Address [Clos [Push; Nth 2; Swap; Nth 1; Times]], Environment []);
  6760. Closure (Address [Clos [Push; Nth 2; Swap; Nth 1; Divide]], Environment []);
  6761. Closure (Address [Clos [Push; Nth 2; Swap; Nth 1; Equal]], Environment [])]
  6762.  
  6763.   As an example, here is the code for some ASL expressions.
  6764.  
  6765. #code_of (expression(lexer(stream_of_string "1;")));;
  6766. - : instruction list = [Quote 1]
  6767.  
  6768. #code_of (expression(lexer(stream_of_string "+ 1 2;")));;
  6769. - : instruction list =
  6770.  [Push; Push; Nth 6; Swap; Quote 1; Apply; Swap; Quote 2; Apply]
  6771.  
  6772.  
  6773.  
  6774.                                     118
  6775.  
  6776.  
  6777.  
  6778. #code_of (expression(lexer(stream_of_string "(\\x.x) ((\\x.x) 0);")));;
  6779. - : instruction list =
  6780.  [Push; Clos [Nth 1]; Swap; Push; Clos [Nth 1]; Swap; Quote 0; Apply; Apply]
  6781.  
  6782. #code_of (expression(lexer(stream_of_string
  6783. #                "+ 1 (if 0 then 2 else 3 fi);")));;
  6784. - : instruction list =
  6785.  [Push; Push; Nth 6; Swap; Quote 1; Apply; Swap; Push; Quote 0;
  6786.   Branch ([Quote 2], [Quote 3]); Apply]
  6787.  
  6788.  
  6789.  
  6790. 16.3 Execution of CAM code
  6791.  
  6792. The main function for executing compiled ASL manages the global environment
  6793. until execution has succeeded.
  6794.  
  6795. #let run (Decl(s,e)) =
  6796. #  (* TYPING *)
  6797. #    reset_vartypes();
  6798. #    let tau =
  6799. #        try asl_typing_expr !global_typing_env e
  6800. #        with TypeClash(t1,t2) ->
  6801. #              let vars=vars_of_type(t1) @ vars_of_type(t2) in
  6802. #              print_string "ASL Type clash between ";
  6803. #              print_type_scheme (Forall(vars,t1));
  6804. #              print_string " and ";
  6805. #              print_type_scheme (Forall(vars,t2));
  6806. #              raise (Failure "ASL typing")
  6807. #           | Unbound s -> raise (TypingBug ("Unbound: "^s)) in
  6808. #    let sigma = generalise_type (!global_typing_env,tau) in
  6809. #  (* PRINTING TYPE INFORMATION *)
  6810. #    print_string "ASL Type of ";
  6811. #    print_string s; print_string " is ";
  6812. #    print_type_scheme sigma; print_newline();
  6813. #  (* COMPILING *)
  6814. #    let code = code_of e in
  6815. #    let state = {Reg=Environment(!global_CAM_env); PC=code; Stack=[]} in
  6816. #  (* EXECUTING *)
  6817. #    let result = try while true do step state done; state.Reg
  6818. #                 with CAM_End v -> v in
  6819. #  (* UPDATING ENVIRONMENTS *)
  6820. #    global_env := s::!global_env;
  6821. #    global_typing_env := sigma::!global_typing_env;
  6822. #    global_CAM_env := result::!global_CAM_env;
  6823. #  (* PRINTING RESULT *)
  6824. #    (match result
  6825. #     with Constant(n) -> print_int n
  6826. #        | Closure(_,_) -> print_string "<funval>"
  6827. #        | _ -> raise (CAMbug "Wrong state configuration"));
  6828. #    print_newline();;
  6829.  
  6830.  
  6831.                                     119
  6832.  
  6833.  
  6834.  
  6835. run : top_asl -> unit = <fun>
  6836.  
  6837. Now, let us run some examples:
  6838.  
  6839. #(* Reinitializing environments *)
  6840. #global_env:=init_env;
  6841. #global_typing_env:=init_typing_env;
  6842. #global_CAM_env:=init_CAM_env;
  6843. #();;
  6844. - : unit = ()
  6845.  
  6846. #run (parse_top "1;");;
  6847. ASL Type of it is Number
  6848. 1
  6849. - : unit = ()
  6850.  
  6851. #run (parse_top "+ 1 2;");;
  6852. ASL Type of it is Number
  6853. 3
  6854. - : unit = ()
  6855.  
  6856. #run (parse_top "(\\f.(\\x.f x)) (\\x. + x 1) 3;");;
  6857. ASL Type of it is Number
  6858. 4
  6859. - : unit = ()
  6860.  
  6861. We may now introduce the Z fixpoint combinator as a predefined function fix.
  6862.  
  6863. #begin
  6864. #  global_env:="fix"::init_env;
  6865. #  global_typing_env:=
  6866. #    (Forall([1],
  6867. #            Arrow(Arrow(TypeVar{Index=1;Value=Unknown},
  6868. #                        TypeVar{Index=1;Value=Unknown}),
  6869. #                  TypeVar{Index=1;Value=Unknown})))
  6870. #   ::init_typing_env;
  6871. #  global_CAM_env:=
  6872. #   (match code_of (expression(lexer(stream_of_string
  6873. #           "\\f.((\\x.f(\\z.(x x)z)) (\\x.f(\\z.(x x)z)));")))
  6874. #    with [Clos(C)] -> Closure(Address(C), Environment [])
  6875. #       | _ -> raise (CAMbug "Wrong code for fix"))
  6876. #   ::init_CAM_env
  6877. #end;;
  6878. Toplevel input:
  6879. >    with [Clos(C)] -> Closure(Address(C), Environment [])
  6880. >               ^
  6881. Warning: the variable C starts with an upper case letter in this pattern.
  6882. - : unit = ()
  6883.  
  6884.  
  6885. #run (parse_top
  6886.  
  6887.  
  6888.                                     120
  6889.  
  6890.  
  6891.  
  6892. #    "let fact be fix (\\f.(\\n. if = n 0 then 1
  6893. #                           else * n (f (- n 1))
  6894. #                           fi));");;
  6895. ASL Type of fact is (Number -> Number)
  6896. <funval>
  6897. - : unit = ()
  6898.  
  6899. #run (parse_top
  6900. #  "let fib be fix (\\f.(\\n. if = n 1 then 1
  6901. #                             else if = n 2 then 1
  6902. #                                  else + (f(- n 1)) (f(- n 2))
  6903. #                                  fi
  6904. #                             fi));");;
  6905. ASL Type of fib is (Number -> Number)
  6906. <funval>
  6907. - : unit = ()
  6908.  
  6909. #run (parse_top "fact 8;");;
  6910. ASL Type of it is Number
  6911. 40320
  6912. - : unit = ()
  6913.  
  6914. #run (parse_top "fib 9;");;
  6915. ASL Type of it is Number
  6916. 34
  6917. - : unit = ()
  6918.  
  6919.   It is of course possible (and desirable) to introduce recursion by using a
  6920. specific syntactic construct, special instructions and a dedicated case to
  6921. the compiling function.  See [26] for efficient compilation of recursion,
  6922. data structures etc.
  6923.  
  6924. Exercise 16.1 Interesting exercises for which we won't give solutions
  6925. consist in enriching according to your taste the ASL language.  Also,
  6926. building a standalone ASL interpreter is a good exercise in modular
  6927. programming.
  6928.  
  6929.  
  6930.  
  6931.  
  6932.  
  6933.  
  6934.  
  6935.  
  6936.  
  6937.  
  6938.  
  6939.  
  6940.  
  6941.  
  6942.  
  6943.  
  6944.  
  6945.                                     121
  6946.  
  6947.  
  6948.  
  6949.  
  6950.  
  6951.  
  6952.  
  6953.  
  6954.  
  6955. Chapter 17
  6956.  
  6957.  
  6958.  
  6959. Answers to exercises
  6960.  
  6961.  
  6962.  
  6963. We give in this chapter one possible solution for each exercise contained in
  6964. this document.  Exercises are referred to by their number and the page where
  6965. they have been proposed:  for example, ``2.1, p.  15'' refers to the first
  6966. exercise in chapter 2; this exercise is located on page 15.
  6967.  
  6968. 3.1, p.  17
  6969.  
  6970. The following (anonymous) functions have the required types:
  6971. #function f -> (f 2)+1;;
  6972. - : (int -> int) -> int = <fun>
  6973.  
  6974. #function m -> (function n -> n+m+1);;
  6975. - : int -> int -> int = <fun>
  6976.  
  6977. #(function f -> (function m -> f(m+1) / 2));;
  6978. - : (int -> int) -> int -> int = <fun>
  6979.  
  6980.  
  6981. 3.2, p.  17
  6982.  
  6983. We must first rename y to z, obtaining:
  6984.  
  6985. (function x -> (function z -> x+z))
  6986.  
  6987. and finally:
  6988.  
  6989. (function y -> (function z -> y+z))
  6990.  
  6991. Without renaming, we would have obtained:
  6992.  
  6993. (function y -> (function y -> y+y))
  6994.  
  6995. which does not denote the same function.
  6996.  
  6997.  
  6998.  
  6999.  
  7000.  
  7001.                                     122
  7002.  
  7003.  
  7004.  
  7005. 3.3, p.  17
  7006.  
  7007. We write successively the reduction steps for each expressions, and then we
  7008. use Caml in order to check the result.
  7009.  
  7010.  -  let x=1+2 in ((function y -> y+x) x);;
  7011.     (function y -> y+(1+2)) (1+2);;
  7012.     (function y -> y+(1+2)) 3;;
  7013.     3+(1+2);;
  7014.     3+3;;
  7015.     6;;
  7016.  
  7017.     Caml says:
  7018.  
  7019. #let x=1+2 in ((function y -> y+x) x);;
  7020. - : int = 6
  7021.  
  7022.  
  7023.  
  7024.  -  let x=1+2 in ((function x -> x+x) x);;
  7025.     (function x -> x+x) (1+2);;
  7026.     3+3;;
  7027.     6;;
  7028.  
  7029.     Caml says:
  7030.  
  7031. #let x=1+2 in ((function x -> x+x) x);;
  7032. - : int = 6
  7033.  
  7034.  
  7035.  
  7036.  -  let f1 = function f2 -> (function x -> f2 x)
  7037.     in let g = function x -> x+1
  7038.        in f1 g 2;;
  7039.     let g = function x -> x+1
  7040.     in function f2 -> (function x -> f2 x) g 2;;
  7041.     (function f2 -> (function x -> f2 x)) (function x -> x+1) 2;;
  7042.     (function x -> (function x -> x+1) x)  2;;
  7043.     (function x -> x+1) 2;;
  7044.     2+1;;
  7045.     3;;
  7046.  
  7047.     Caml says:
  7048.  
  7049. #let f1 = function f2 -> (function x -> f2 x)
  7050. #in let g = function x -> x+1
  7051. #   in f1 g 2;;
  7052. - : int = 3
  7053.  
  7054.  
  7055.  
  7056.  
  7057.  
  7058.                                     123
  7059.  
  7060.  
  7061.  
  7062. 4.1, p.  29
  7063.  
  7064. To compute the surface area of a rectangle and the volume of a sphere:
  7065.  
  7066. #let surface_rect len wid = len * wid;;
  7067. surface_rect : int -> int -> int = <fun>
  7068.  
  7069. #let pi = 4.0 *. atan 1.0;;
  7070. pi : float = 3.14159265359
  7071.  
  7072. #let volume_sphere r = 4.0 /. 3.0 *. pi *. (power r 3.);;
  7073. volume_sphere : float -> float = <fun>
  7074.  
  7075.  
  7076. 4.2, p.  29
  7077.  
  7078. In a call-by-value language without conditional construct (and without sum
  7079. types), all programs involving a recursive definition never terminate.
  7080.  
  7081. 4.3, p.  29
  7082.  
  7083. #let rec factorial n = if n=1 then 1 else n*(factorial(n-1));;
  7084. factorial : int -> int = <fun>
  7085.  
  7086. #factorial 5;;
  7087. - : int = 120
  7088.  
  7089. #let tail_recursive_factorial n =
  7090. #  let rec fact n m = if n=1 then m else fact (n-1) (n*m)
  7091. #  in fact n 1;;
  7092. tail_recursive_factorial : int -> int = <fun>
  7093.  
  7094. #tail_recursive_factorial 5;;
  7095. - : int = 120
  7096.  
  7097.  
  7098. 4.4, p.  29
  7099.  
  7100. #let rec fibonacci n =
  7101. #  if n=1 then 1
  7102. #         else if n=2 then 1
  7103. #                     else fibonacci(n-1) + fibonacci(n-2);;
  7104. fibonacci : int -> int = <fun>
  7105.  
  7106. #fibonacci 20;;
  7107. - : int = 6765
  7108.  
  7109.  
  7110.  
  7111.  
  7112.  
  7113.  
  7114.                                     124
  7115.  
  7116.  
  7117.  
  7118. 4.5, p.  29
  7119.  
  7120. #let compose f g = function x -> f (g (x));;
  7121. compose : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b = <fun>
  7122.  
  7123. #let curry f = function x -> (function y -> f(x,y));;
  7124. curry : ('a * 'b -> 'c) -> 'a -> 'b -> 'c = <fun>
  7125.  
  7126. #let uncurry f = function (x,y) -> f x y;;
  7127. uncurry : ('a -> 'b -> 'c) -> 'a * 'b -> 'c = <fun>
  7128.  
  7129. #uncurry compose;;
  7130. - : ('_a -> '_b) * ('_c -> '_a) -> '_c -> '_b = <fun>
  7131.  
  7132. #compose curry uncurry;;
  7133. - : ('_a -> '_b -> '_c) -> '_a -> '_b -> '_c = <fun>
  7134.  
  7135. #compose uncurry curry;;
  7136. - : ('_a * '_b -> '_c) -> '_a * '_b -> '_c = <fun>
  7137.  
  7138.  
  7139. 5.1, p.  34
  7140.  
  7141. #let rec combine =
  7142. #  function [],[] -> []
  7143. #         | (x1::l1),(x2::l2) -> (x1,x2)::(combine(l1,l2))
  7144. #         | _ -> raise (Failure "combine: lists of different length");;
  7145. combine : 'a list * 'b list -> ('a * 'b) list = <fun>
  7146.  
  7147. #combine ([1;2;3],["a";"b";"c"]);;
  7148. - : (int * string) list = [1, "a"; 2, "b"; 3, "c"]
  7149.  
  7150. #combine ([1;2;3],["a";"b"]);;
  7151. Uncaught exception: Failure "combine: lists of different length"
  7152.  
  7153.  
  7154. 5.2, p.  35
  7155.  
  7156. #let rec sublists =
  7157. #    function [] -> [[]]
  7158. #           | x::l -> let sl = sublists l
  7159. #                     in sl @ (map (fun l -> x::l) sl);;
  7160. sublists : 'a list -> 'a list list = <fun>
  7161.  
  7162. #sublists [];;
  7163. - : '_a list list = [[]]
  7164.  
  7165. #sublists [1;2;3];;
  7166. - : int list list = [[]; [3]; [2]; [2; 3]; [1]; [1; 3]; [1; 2]; [1; 2; 3]]
  7167.  
  7168. #sublists ["a"];;
  7169.  
  7170.  
  7171.                                     125
  7172.  
  7173.  
  7174.  
  7175. - : string list list = [[]; ["a"]]
  7176.  
  7177.  
  7178. 6.1, p.  45
  7179.  
  7180. #type ('a,'b) btree = Leaf of 'b
  7181. #                   | Btree of ('a,'b) node
  7182. #and ('a,'b) node = {Op:'a;
  7183. #                    Son1: ('a,'b) btree;
  7184. #                    Son2: ('a,'b) btree};;
  7185. Type btree defined.
  7186. Type node defined.
  7187.  
  7188. #let rec nodes_and_leaves =
  7189. #    function Leaf x -> ([],[x])
  7190. #           | Btree {Op=x; Son1=s1; Son2=s2} ->
  7191. #                let (nodes1,leaves1) = nodes_and_leaves s1
  7192. #                and (nodes2,leaves2) = nodes_and_leaves s2
  7193. #                in (x::nodes1@nodes2, leaves1@leaves2);;
  7194. nodes_and_leaves : ('a, 'b) btree -> 'a list * 'b list = <fun>
  7195.  
  7196. #nodes_and_leaves (Btree {Op="+"; Son1=Leaf 1; Son2=Leaf 2});;
  7197. - : string list * int list = ["+"], [1; 2]
  7198.  
  7199.  
  7200. 6.2, p.  45
  7201.  
  7202. #let rec map_btree f g = function
  7203. #      Leaf x -> Leaf (f x)
  7204. #    | Btree {Op=op; Son1=s1; Son2=s2}
  7205. #               -> Btree {Op=g op; Son1=map_btree f g s1;
  7206. #                                  Son2=map_btree f g s2};;
  7207. map_btree : ('a -> 'b) -> ('c -> 'd) -> ('c, 'a) btree -> ('d, 'b) btree =
  7208.  <fun>
  7209.  
  7210.  
  7211. 6.3, p.  45
  7212.  
  7213. We need to give a functional interpretation to btree data constructors.  We
  7214. use f (resp.  g) to denote the function associated to the Leaf (resp.
  7215. Btree) data constructor, obtaining the following Caml definition:
  7216.  
  7217. #let rec btree_it f g = function
  7218. #      Leaf x -> f x
  7219. #    | Btree{Op=op; Son1=s1; Son2=s2}
  7220. #              -> g op (btree_it f g s1) (btree_it f g s2)
  7221. #;;
  7222. btree_it : ('a -> 'b) -> ('c -> 'b -> 'b -> 'b) -> ('c, 'a) btree -> 'b =
  7223.  <fun>
  7224.  
  7225.  
  7226.  
  7227.                                     126
  7228.  
  7229.  
  7230.  
  7231. #btree_it (function x -> x)
  7232. #         (function "+" -> prefix +
  7233. #                 | _ -> raise (Failure "Unknown op"))
  7234. #         (Btree {Op="+"; Son1=Leaf 1; Son2=Leaf 2});;
  7235. - : int = 3
  7236.  
  7237.  
  7238. 7.1, p.  53
  7239.  
  7240. #type ('a,'b) lisp_cons = {mutable Car:'a; mutable Cdr:'b};;
  7241. Type lisp_cons defined.
  7242.  
  7243. #let car p = p.Car
  7244. #and cdr p = p.Cdr
  7245. #and rplaca p v = p.Car <- v
  7246. #and rplacd p v = p.Cdr <- v;;
  7247. car : ('a, 'b) lisp_cons -> 'a = <fun>
  7248. cdr : ('a, 'b) lisp_cons -> 'b = <fun>
  7249. rplaca : ('a, 'b) lisp_cons -> 'a -> unit = <fun>
  7250. rplacd : ('a, 'b) lisp_cons -> 'b -> unit = <fun>
  7251.  
  7252. #let p = {Car=1; Cdr=true};;
  7253. p : (int, bool) lisp_cons = {Car=1; Cdr=true}
  7254.  
  7255. #rplaca p 2;;
  7256. - : unit = ()
  7257.  
  7258. #p;;
  7259. - : (int, bool) lisp_cons = {Car=2; Cdr=true}
  7260.  
  7261.  
  7262. 7.2, p.  54
  7263.  
  7264. #let stamp_counter = ref 0;;
  7265. stamp_counter : int ref = ref 0
  7266.  
  7267. #let stamp () =
  7268. #  stamp_counter := 1 + !stamp_counter; !stamp_counter;;
  7269. stamp : unit -> int = <fun>
  7270.  
  7271. #stamp();;
  7272. - : int = 1
  7273.  
  7274. #stamp();;
  7275. - : int = 2
  7276.  
  7277.  
  7278. 7.3, p.  54
  7279.  
  7280. #let exchange t i j =
  7281.  
  7282.  
  7283.                                     127
  7284.  
  7285.  
  7286.  
  7287. #  let v = t.(i) in vect_assign t i t.(j); vect_assign t j v
  7288. #;;
  7289. exchange : 'a vect -> int -> int -> unit = <fun>
  7290.  
  7291. #let quick_sort t =
  7292. #  let rec quick lo hi =
  7293. #    if lo < hi
  7294. #    then begin
  7295. #          let i = ref lo
  7296. #          and j = ref hi
  7297. #          and p = t.(hi) in
  7298. #          while !i < !j
  7299. #           do
  7300. #            while !i < hi & t.(!i) <=. p do incr i done;
  7301. #            while !j > lo & p <=. t.(!j) do decr j done;
  7302. #            if !i < !j then exchange t !i !j
  7303. #           done;
  7304. #          exchange t hi !i;
  7305. #          quick lo (!i - 1);
  7306. #          quick (!i + 1) hi
  7307. #         end
  7308. #     else ()
  7309. #  in quick 0 (vect_length t - 1)
  7310. #;;
  7311. quick_sort : float vect -> unit = <fun>
  7312.  
  7313. #let a = [| 2.0; 1.5; 4.0; 0.0; 10.0; 1.0 |];;
  7314. a : float vect = [|2.0; 1.5; 4.0; 0.0; 10.0; 1.0|]
  7315.  
  7316. #quick_sort a;;
  7317. - : unit = ()
  7318.  
  7319. #a;;
  7320. - : float vect = [|0.0; 1.0; 1.5; 2.0; 4.0; 10.0|]
  7321.  
  7322.  
  7323. 8.1, p.  58
  7324.  
  7325. #let rec find_succeed f = function
  7326. #      [] -> raise (Failure "find_succeed")
  7327. #    | x::l -> try f x; x with _ -> find_succeed f l
  7328. #;;
  7329. find_succeed : ('a -> 'b) -> 'a list -> 'a = <fun>
  7330.  
  7331. #let hd = function [] -> raise (Failure "empty") | x::l -> x;;
  7332. hd : 'a list -> 'a = <fun>
  7333.  
  7334. #find_succeed hd [[];[];[1;2];[3;4]];;
  7335. - : int list = [1; 2]
  7336.  
  7337.  
  7338.  
  7339.  
  7340.                                     128
  7341.  
  7342.  
  7343.  
  7344. 8.2, p.  58
  7345.  
  7346. #let rec map_succeed f = function
  7347. #      [] -> []
  7348. #    | h::t -> try (f h)::(map_succeed f t)
  7349. #              with _ ->  map_succeed f t;;
  7350. map_succeed : ('a -> 'b) -> 'a list -> 'b list = <fun>
  7351.  
  7352. #map_succeed hd [[];[1];[2;3];[4;5;6]];;
  7353. - : int list = [1; 2; 4]
  7354.  
  7355.  
  7356. 9.1, p.  65
  7357.  
  7358. The first function (copy) that we define assumes that its arguments are
  7359. respectively the input and the output channel.  They are assumed to be
  7360. already opened.
  7361.  
  7362. #let copy inch outch =
  7363. #  (* inch and outch are supposed to be opened channels *)
  7364. #  try (* actual copying *)
  7365. #      while true
  7366. #      do output_char outch (input_char inch)
  7367. #      done
  7368. #   with End_of_file -> (* Normal termination *)
  7369. #             raise End_of_file
  7370. #      | sys__Sys_error msg -> (* Abnormal termination *)
  7371. #             prerr_endline msg;
  7372. #             raise (Failure "cp")
  7373. #      | _ -> (* Unknow exception, maybe interruption? *)
  7374. #             prerr_endline "Unknown error while copying";
  7375. #             raise (Failure "cp")
  7376. #;;
  7377. copy : in_channel -> out_channel -> unit = <fun>
  7378.  
  7379. The next function opens channels connected to its filename arguments, and
  7380. calls copy on these channels.  The advantage of dividing the code into two
  7381. functions is that copy performs the actual work, and can be reused in
  7382. different applications, while the role of cp is more ``administrative'' in
  7383. the sense that it does nothing but opening and closing channels and printing
  7384. possible error messages.
  7385.  
  7386. #let cp f1 f2 =
  7387. #  (* Opening channels, f1 first, then f2 *)
  7388. #  let inch =
  7389. #      try open_in f1
  7390. #      with sys__Sys_error msg ->
  7391. #                prerr_endline (f1^": "^msg);
  7392. #                raise (Failure "cp")
  7393. #         | _ -> prerr_endline ("Unknown exception while opening "^f1);
  7394. #                raise (Failure "cp")
  7395.  
  7396.  
  7397.                                     129
  7398.  
  7399.  
  7400.  
  7401. #  in
  7402. #  let outch =
  7403. #      try open_out f2
  7404. #      with sys__Sys_error msg ->
  7405. #                close_in inch;
  7406. #                prerr_endline (f2^": "^msg);
  7407. #                raise (Failure "cp")
  7408. #         | _ -> close_in inch;
  7409. #                prerr_endline ("Unknown exception while opening "^f2);
  7410. #                raise (Failure "cp")
  7411. #  in (* Copying and then closing *)
  7412. #     try copy inch outch
  7413. #     with End_of_file -> close_in inch; close_out outch
  7414. #                        (* close_out flushes *)
  7415. #        | exc -> close_in inch; close_out outch; raise exc
  7416. #;;
  7417. cp : string -> string -> unit = <fun>
  7418.  
  7419. Let us try cp:
  7420.  
  7421. #cp "/etc/passwd" "/tmp/foo";;
  7422. - : unit = ()
  7423.  
  7424. #cp "/tmp/foo" "/foo";;
  7425. /foo: /foo: Permission denied
  7426. Uncaught exception: Failure "cp"
  7427.  
  7428. The last example failed because a regular user is not allowed to write at
  7429. the root of the file system.
  7430.  
  7431. 9.2, p.  65
  7432.  
  7433. As in the previous exercise, the function count performs the actual
  7434. counting.  It works on an input channel and returns a pair of integers.
  7435.  
  7436. #let count inch =
  7437. #    let chars = ref 0
  7438. #    and lines = ref 0 in
  7439. #    try
  7440. #      while true do
  7441. #        let c = input_char inch in
  7442. #          chars := !chars + 1;
  7443. #          if c = `\n` then lines := !lines + 1 else ()
  7444. #      done;
  7445. #      (!chars, !lines)
  7446. #    with End_of_file -> (!chars, !lines)
  7447. #;;
  7448. count : in_channel -> int * int = <fun>
  7449.  
  7450. The function wc opens a channel on its filename argument, calls count and
  7451. prints the result.
  7452.  
  7453.  
  7454.                                     130
  7455.  
  7456.  
  7457.  
  7458. #let wc f =
  7459. #    let inch =
  7460. #       try open_in f
  7461. #       with sys__Sys_error msg ->
  7462. #                prerr_endline (f^": "^msg);
  7463. #                raise (Failure "wc")
  7464. #         | _ -> prerr_endline ("Unknown exception while opening "^f);
  7465. #                raise (Failure "wc")
  7466. #  in let (chars,lines) = count inch
  7467. #     in   print_int chars;
  7468. #          print_string " characters, ";
  7469. #          print_int lines;
  7470. #          print_string " lines.\n"
  7471. #;;
  7472. wc : string -> unit = <fun>
  7473.  
  7474. Counting /etc/passwd gives:
  7475.  
  7476. #wc "/etc/passwd";;
  7477. 32474 characters, 392 lines.
  7478. - : unit = ()
  7479.  
  7480.  
  7481. 10.1, p.  78
  7482.  
  7483. Let us recall the definitions of the type token and of the lexical analyzer:
  7484.  
  7485. #type token =
  7486. #  PLUS | MINUS | TIMES | DIV | LPAR | RPAR
  7487. #| INT of int;;
  7488. Type token defined.
  7489.  
  7490. #(* Spaces *)
  7491. #let rec spaces = function
  7492. #  [< '` `|`\t`|`\n`; spaces _ >] -> ()
  7493. #| [< >] -> ();;
  7494. spaces : char stream -> unit = <fun>
  7495.  
  7496. #(* Integers *)
  7497. #let int_of_digit = function
  7498. #  `0`..`9` as c -> (int_of_char c) - (int_of_char `0`)
  7499. #| _ -> raise (Failure "not a digit");;
  7500. int_of_digit : char -> int = <fun>
  7501.  
  7502. #let rec integer n = function
  7503. #  [< ' `0`..`9` as c; (integer (10*n + int_of_digit c)) r >] -> r
  7504. #| [< >] -> n;;
  7505. integer : int -> char stream -> int = <fun>
  7506.  
  7507. #(* The lexical analyzer *)
  7508. #let rec lexer s = match s with
  7509.  
  7510.  
  7511.                                     131
  7512.  
  7513.  
  7514.  
  7515. #  [< '`(`; spaces _ >] -> [< 'LPAR; lexer s >]
  7516. #| [< '`)`; spaces _ >] -> [< 'RPAR; lexer s >]
  7517. #| [< '`+`; spaces _ >] -> [< 'PLUS; lexer s >]
  7518. #| [< '`-`; spaces _ >] -> [< 'MINUS; lexer s >]
  7519. #| [< '`*`; spaces _ >] -> [< 'TIMES; lexer s >]
  7520. #| [< '`/`; spaces _ >] -> [< 'DIV; lexer s >]
  7521. #| [< '`0`..`9` as c; (integer (int_of_digit c)) n; spaces _ >]
  7522. #                                -> [< 'INT n; lexer s >];;
  7523. lexer : char stream -> token stream = <fun>
  7524.  
  7525. The parser has the same shape as the grammar:
  7526.  
  7527. #let rec expr = function
  7528. #  [< 'INT n >] -> n
  7529. #| [< 'PLUS; expr e1; expr e2 >] -> e1+e2
  7530. #| [< 'MINUS; expr e1; expr e2 >] -> e1-e2
  7531. #| [< 'TIMES; expr e1; expr e2 >] -> e1*e2
  7532. #| [< 'DIV; expr e1; expr e2 >] -> e1/e2;;
  7533. expr : token stream -> int = <fun>
  7534.  
  7535. #expr (lexer (stream_of_string "1"));;
  7536. - : int = 1
  7537.  
  7538. #expr (lexer (stream_of_string "+ 1 * 2 4"));;
  7539. - : int = 9
  7540.  
  7541.  
  7542. 10.2, p.  78
  7543.  
  7544. The only new function that we need is a function taking as argument a
  7545. character stream, and returning the first identifier of that stream.  It
  7546. could be written as:
  7547.  
  7548. #let ident_buf = make_string 8 ` `;;
  7549. ident_buf : string = "        "
  7550.  
  7551. #let rec ident len = function
  7552. #  [< ' `a`..`z`|`A`..`Z` as c;
  7553. #     (if len >= 8 then ident len
  7554. #      else begin
  7555. #            set_nth_char ident_buf len c;
  7556. #            ident (succ len)
  7557. #           end) s >] -> s
  7558. #| [< >] -> sub_string ident_buf 0 len;;
  7559. ident : int -> char stream -> string = <fun>
  7560.  
  7561. The lexical analyzer will first try to recognize an alphabetic character c,
  7562. then put c at position 0 of ident_buf, and call ident 1 on the rest of the
  7563. character stream.  Alphabetic characters encountered will be stored in the
  7564. string buffer ident_buf, up to the 8th.  Further alphabetic characters will
  7565. be skipped.  Finally, a substring of the buffer will be returned as result.
  7566.  
  7567.  
  7568.                                     132
  7569.  
  7570.  
  7571.  
  7572. #let s = stream_of_string "toto 1";;
  7573. s : char stream = <abstr>
  7574.  
  7575. #ident 0 s;;
  7576. - : string = "toto"
  7577.  
  7578. #(* Let us see what remains in the stream *)
  7579. #match s with [< 'c >] -> c;;
  7580. - : char = ` `
  7581.  
  7582. #let s = stream_of_string "LongIdentifier ";;
  7583. s : char stream = <abstr>
  7584.  
  7585. #ident 0 s;;
  7586. - : string = "LongIden"
  7587.  
  7588. #match s with [< 'c >] -> c;;
  7589. - : char = ` `
  7590.  
  7591.   The definitions of the new token type and of the lexical analyzer is
  7592. trivial, and we shall omit them.  A slightly more complex lexical analyzer
  7593. recognizing identifiers (lowercase only) is given in section 12.2.1 in this
  7594. part.
  7595.  
  7596. 11.1, p.  83
  7597.  
  7598. (* main.ml *)
  7599. let chars = counter__new 0;;
  7600. let lines = counter__new 0;;
  7601.  
  7602. let count_file filename =
  7603.   let in_chan = open_in filename in
  7604.     try
  7605.       while true do
  7606.         let c = input_char in_chan in
  7607.           counter__incr chars;
  7608.           if c = `\n` then counter__incr lines
  7609.       done
  7610.     with End_of_file ->
  7611.       close_in in_chan
  7612. ;;
  7613.  
  7614. for i = 1 to vect_length sys__command_line - 1 do
  7615.   count_file sys__command_line.(i)
  7616. done;
  7617. print_int (counter__read chars);
  7618. print_string " characters, ";
  7619. print_int (counter__read lines);
  7620. print_string " lines.\n";
  7621. exit 0;;
  7622.  
  7623.  
  7624.  
  7625.                                     133
  7626.  
  7627.  
  7628.  
  7629.  
  7630.  
  7631.  
  7632.  
  7633.  
  7634.  
  7635. Chapter 18
  7636.  
  7637.  
  7638.  
  7639. Conclusions and further reading
  7640.  
  7641.  
  7642.  
  7643. We have not been exhaustive in the description of the Caml Light features.
  7644. We only introduced general concepts in functional programming, and we have
  7645. insisted on the features used in the prototyping of ASL: a tiny model of
  7646. Caml Light typing and semantics.
  7647.   The reference manual [20] provides an exhaustive description of the Caml
  7648. Light language, its libraries, commands and extensions.
  7649.   Those who read French are referred to [38], a progressive, but thorough
  7650. introduction to programming in Caml Light, with many interesting examples,
  7651. and to [21], the French edition of the Caml Light reference manual.
  7652.   Description about ``Caml Strong'' and useful information about programming
  7653. in Caml can be found in [9] and [37].
  7654.   An introduction to lambda-calculus and type systems can be found in [17],
  7655. [12] and [4].
  7656.   The description of the implementation of call-by-value functional
  7657. programming languages can be found in [19].
  7658.   The implementation of lazy functional languages is described in [29]
  7659. (translated in French as [30]).  An introduction to programming in lazy
  7660. functional languages can be found in [5].
  7661.  
  7662.  
  7663.  
  7664.  
  7665.  
  7666.  
  7667.  
  7668.  
  7669.  
  7670.  
  7671.  
  7672.  
  7673.  
  7674.  
  7675.  
  7676.  
  7677.  
  7678.  
  7679.  
  7680.  
  7681.                                     134
  7682.  
  7683.  
  7684.  
  7685.  
  7686.  
  7687.  
  7688.  
  7689.  
  7690.  
  7691.  
  7692. Bibliography
  7693.  
  7694.  
  7695.  
  7696.  [1] H. Abelson and G.J. Sussman. Structure and Interpretation of Computer
  7697.      Programs. The MIT Press, 1985.
  7698.  
  7699.  [2] A. Aho, R. Sethi, and J. Ullman. Compilers:  Principles, Techniques
  7700.      and Tools. Addison Wesley, 1986.
  7701.  
  7702.  [3] J. Backus. Can programming be liberated from the Von Neumann style?  A
  7703.      functional style and its algebra of programs. In Communications of the
  7704.      ACM, volume 21, pages 133--140, 1978.
  7705.  
  7706.  [4] H.P. Barendregt. The Lambda-Calculus:  Its Syntax and Semantics,
  7707.      volume 103 of Studies in Logic and the Foundations of Mathematics.
  7708.      North-Holland, 1984.
  7709.  
  7710.  [5] R. Bird and P. Wadler. Introduction to Functional Programming. Series
  7711.      in Computer Science. Prentice-Hall International, 1986.
  7712.  
  7713.  [6] A. Church. The Calculi of Lambda Conversion. Princeton University
  7714.      Press, 1941.
  7715.  
  7716.  [7] D. Clement, J. Despeyroux, T. Despeyroux, and G. Kahn. A simple
  7717.      applicative language:  Mini-ML. In Proceedings of the ACM
  7718.      International Conference on Lisp and Functional Programming, pages
  7719.      13--27, 1986.
  7720.  
  7721.  [8] G. Cousineau, P.-L. Curien, and M. Mauny. The categorical abstract
  7722.      machine. In Functional Programming Languages and Computer
  7723.      Architecture, number 201 in Lecture Notes in Computer Science, pages
  7724.      50--64. Springer Verlag, 1985.
  7725.  
  7726.  [9] G. Cousineau and G. Huet. The CAML primer. Technical Report 122,
  7727.      INRIA, 1990.
  7728.  
  7729. [10] N. De Bruijn. Lambda-calculus notation with nameless dummies, a tool
  7730.      for automatic formula manipulation. Indag. Math., 1962.
  7731.  
  7732. [11] M. Gordon, R. Milner, L. Morris, M. Newey, and C. Wadworth. A
  7733.      metalanguage for interactive proofs in LCF. In Proceedings of ACM
  7734.      Symposium on Principles of Programming Languages, pages 119--130,
  7735.      1978.
  7736.  
  7737.  
  7738.                                     135
  7739.  
  7740.  
  7741.  
  7742. [12] J.R. Hindley and J.P. Seldin. Introduction to Combinators and
  7743.      l-calculus. London Mathematical Society, Student Texts. Cambridge
  7744.      University Press, 1986.
  7745.  
  7746. [13] C.A.R. Hoare. Quicksort. Computer Journal, 5(1), 1962.
  7747.  
  7748. [14] W.A. Howard. The formulae-as-type notion of construction, pages
  7749.      479--490. Academic Press, 1980.
  7750.  
  7751. [15] P. Hudak and P. Wadler. Report on the programming language Haskell.
  7752.      Technical Report YALEU/DCS/RR-777, Yale University, 1990.
  7753.  
  7754. [16] T. Johnsson. Efficient compilation of lazy evaluation. In Proceedings
  7755.      of ACM Conference on Compiler Construction, pages 58--69, 1984.
  7756.  
  7757. [17] J.-L. Krivine. Lambda-calcul, types et modeles. Etudes et recherches
  7758.      en informatique. Masson, 1990.
  7759.  
  7760. [18] P. Landin. The next 700 programming languages. In Communications of
  7761.      the ACM, volume 9, pages 157--164, 1966.
  7762.  
  7763. [19] X. Leroy. The ZINC experiment:  an economical implementation of the ML
  7764.      language. Technical Report 117, INRIA, 1990.
  7765.  
  7766. [20] X. Leroy. The Caml Light system, release 0.6 --- Documentation and
  7767.      user's manual. Technical report, INRIA, 1993. Included in the Caml
  7768.      Light 0.6 distribution.
  7769.  
  7770. [21] X. Leroy and P. Weis. Manuel de reference du langage Caml.
  7771.      InterEditions, 1993.
  7772.  
  7773. [22] J. MacCarthy. Lisp 1.5 Programmer's Manual. MIT Press, Cambridge,
  7774.      Mass., 1962.
  7775.  
  7776. [23] D. MacQueen. Modules for Standard ML. In Proceedings of the ACM
  7777.      Conference on Lisp and Functional Programming, 1984.
  7778.  
  7779. [24] M. Mauny. Functional programming using CAML. Technical Report 129,
  7780.      INRIA, 1991.
  7781.  
  7782. [25] M. Mauny and D. de Rauglaudre. Parsers in ML. In Proceedings of the
  7783.      ACM Conference on Lisp and Functional Programming, 1992.
  7784.  
  7785. [26] M. Mauny and A. Suarez. Implementing functional languages in the
  7786.      categorical abstract machine. In Proceedings of the ACM International
  7787.      Conference on Lisp and Functional Programming, pages 266--278, 1986.
  7788.  
  7789. [27] R. Milner. A theory of type polymorphism in programming. J. Comput.
  7790.      Syst. Sci., 17:348--375, 1978.
  7791.  
  7792. [28] R. Milner. A proposal for Standard ML. In Proceedings of the ACM
  7793.  
  7794.  
  7795.                                     136
  7796.  
  7797.  
  7798.  
  7799.      Conference on Lisp and Functional Programming, 1987.
  7800.  
  7801. [29] S.L. Peyton-Jones. The Implementation of Functional Programming
  7802.      Languages. Series in Computer Science. Prentice-Hall International,
  7803.      1987.
  7804.  
  7805. [30] S.L. Peyton-Jones. Mise en  uvre des langages fonctionnels de
  7806.      programmation. Manuels Informatiques Masson. Masson, 1990.
  7807.  
  7808. [31] J. Rees and W. Clinger. The revised3 report on the algorithmic
  7809.      language Scheme. In SIGPLAN Notices, volume 21, 1987.
  7810.  
  7811. [32] J. A. Robinson. Computational logic:  the unification computation. In
  7812.      Machine Intelligence, volume 6 of American Elsevier. B. Meltzer and D.
  7813.      Mitchie (Eds), 1971.
  7814.  
  7815. [33] R. Sedgewick. Algorithms. Addison Wesley, 1988.
  7816.  
  7817. [34] D. Turner. SASL language manual. Technical report, St Andrews
  7818.      University, 1976.
  7819.  
  7820. [35] D. Turner. Recursion equations as a programming language, pages 1--28.
  7821.      Cambridge University Press, 1982.
  7822.  
  7823. [36] D. Turner. Miranda:  a non-strict functional language with polymorphic
  7824.      types. In Functional Programming Languages and Computer Architecture,
  7825.      number 201 in Lecture Notes in Computer Science, pages 1--16. Springer
  7826.      Verlag, 1985.
  7827.  
  7828. [37] P. Weis, M.V. Aponte, A. Laville, M. Mauny, and A. Suarez. The CAML
  7829.      reference manual. Technical Report 121, INRIA, 1990.
  7830.  
  7831. [38] P. Weis and X. Leroy. Le langage Caml. InterEditions, 1993.
  7832.  
  7833.  
  7834.  
  7835.  
  7836.  
  7837.  
  7838.  
  7839.  
  7840.  
  7841.  
  7842.  
  7843.  
  7844.  
  7845.  
  7846.  
  7847.  
  7848.  
  7849.  
  7850.  
  7851.  
  7852.                                     137
  7853.